Backend Development 8 min read

Implementing Real‑Time Communication with Workerman and GatewayWorker Using WebSocket in PHP

This tutorial explains how to use the Workerman PHP socket framework and GatewayWorker to replace HTTP long‑polling with WebSocket‑based real‑time communication, covering protocol basics, short vs. long connections, integration with MVC frameworks, and complete client‑ and server‑side code examples.

Laravel Tech Community
Laravel Tech Community
Laravel Tech Community
Implementing Real‑Time Communication with Workerman and GatewayWorker Using WebSocket in PHP

The article introduces Workerman and GatewayWorker as high‑performance PHP socket server frameworks that enable WebSocket communication, allowing developers to replace traditional AJAX long‑polling with persistent connections for real‑time messaging in any PHP project, whether based on ThinkPHP, Laravel, Yii, or other platforms.

It first reviews the TCP/IP protocol suite, describing the network, transport, and application layers, and lists common protocols such as IP, ICMP, ARP, TCP, UDP, HTTP, FTP, and DNS.

Short connections are defined as the typical request‑response cycle where a socket is opened, data is transferred, and the connection is immediately closed, exemplified by standard HTTP interactions.

Long connections keep the socket open after the initial handshake, allowing multiple data exchanges without repeated handshakes; they are useful for frequent, point‑to‑point communication but consume more server resources.

HTTP can also maintain persistent connections using the Connection: keep-alive header (HTTP/1.1 default), though it remains stateless and less reliable for push scenarios.

The article discusses when to choose short versus long connections: short connections suit high‑concurrency web traffic where each request is independent, while long connections are better for frequent, low‑volume interactions such as database connections or real‑time chat.

Workerman is described as an open‑source, pure‑PHP socket server supporting TCP long connections, WebSocket, HTTP, custom protocols, and asynchronous components like MySQL, Redis, and message queues, making it suitable for mobile apps, IoT, game servers, and more.

Integration steps with an MVC framework (illustrated with ThinkPHP) are outlined: 1) Deploy Workerman independently; 2) Serve web pages via HTTP; 3) Use JavaScript on the client to open a WebSocket to Workerman; 4) Authenticate the socket with a user ID; 5) Push data from the PHP application to the client only when needed; 6) Keep other requests handled by the original MVC framework.

Client‑side JavaScript example (using Socket.IO):

// Connect to the Workerman server
var socket = io('http://127.0.0.1:2120');

// User identifier for targeted pushes
uid = 123;

// After connection, log in with the uid
socket.on('connect', function(){
    socket.emit('login', uid);
});

// Handle incoming messages from the server
socket.on('new_msg', function(msg){
    console.log('收到消息:' + msg); // custom business logic here
});

PHP code to send a push message from the application:

// Target UID (empty means broadcast to all online users)
$to_uid = "123";

// Push API endpoint
$push_api_url = "http://127.0.0.1:2121/";

$post_data = array(
    "type" => "publish",
    "content" => "数据",
    "to" => $to_uid,
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $push_api_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Expect:"));
$return = curl_exec($ch);
curl_close($ch);
var_export($return);

Core Workerman push implementation (GatewayWorker side):

// Global map of UID => connection objects
$uidConnectionMap = array();
$last_online_count = 0;

$sender_io = new SocketIO(2120);

$sender_io->on('workerStart', function(){
    $inner_http_worker = new Worker('http://0.0.0.0:2121');
    $inner_http_worker->onMessage = function($http_connection, $data){
        global $uidConnectionMap;
        $_POST = $_POST ? $_POST : $_GET;
        switch(@$_POST['type']){
            case 'publish':
                global $sender_io;
                $to = @$_POST['to'];
                $_POST['content'] = htmlspecialchars(@$_POST['content']);
                if($to){
                    $sender_io->to($to)->emit('new_msg', $_POST['content']);
                }else{
                    $sender_io->emit('new_msg', @$_POST['content']);
                }
                if($to && !isset($uidConnectionMap[$to])){
                    return $http_connection->send('offline');
                }else{
                    return $http_connection->send('ok');
                }
                break;
        }
        return $http_connection->send('fail');
    };
});

if(!defined('GLOBAL_START')){
    Worker::runAll();
}

The final summary advises treating Workerman as a push channel that is invoked only when the application needs to push data to browsers, keeping all business logic inside the original MVC framework while leveraging Workerman for efficient, persistent communication.

Backend DevelopmentWebSocketPHPReal-time CommunicationLong ConnectionWorkerman
Laravel Tech Community
Written by

Laravel Tech Community

Specializing in Laravel development, we continuously publish fresh content and grow alongside the elegant, stable Laravel framework.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.