workerman
An asynchronous event driven PHP socket framework. Supports HTTP, Websocket, SSL and other custom protocols.
Top Related Projects
Event-driven, non-blocking I/O with PHP.
A non-blocking concurrency framework for PHP applications. 🐘
🚀 Coroutine-based concurrency library for PHP
Cross-platform asynchronous I/O
Node.js JavaScript runtime ✨🐢🚀✨
Quick Overview
Workerman is a high-performance PHP socket framework for building fast, scalable network applications. It supports multiple protocols and provides an event-driven, asynchronous programming model for developing real-time applications such as chat servers, game servers, and IoT platforms.
Pros
- High performance and low resource consumption
- Easy to use with a simple API
- Supports multiple protocols (HTTP, WebSocket, TCP, UDP)
- Cross-platform compatibility (Linux, macOS, Windows)
Cons
- Requires PHP CLI and some extensions to be installed
- Limited built-in features compared to full-stack frameworks
- Learning curve for developers new to asynchronous programming
- Documentation primarily in Chinese, with limited English resources
Code Examples
- Creating a simple HTTP server:
use Workerman\Worker;
$http_worker = new Worker("http://0.0.0.0:2345");
$http_worker->onMessage = function($connection, $data) {
$connection->send("Hello World!");
};
Worker::runAll();
- Implementing a WebSocket server:
use Workerman\Worker;
$ws_worker = new Worker("websocket://0.0.0.0:2346");
$ws_worker->onConnect = function($connection) {
echo "New connection\n";
};
$ws_worker->onMessage = function($connection, $data) {
$connection->send("Received: $data");
};
Worker::runAll();
- Creating a custom protocol server:
use Workerman\Worker;
$custom_worker = new Worker("tcp://0.0.0.0:2347");
$custom_worker->onMessage = function($connection, $data) {
if ($data === "ping") {
$connection->send("pong");
}
};
Worker::runAll();
Getting Started
-
Install Workerman using Composer:
composer require workerman/workerman
-
Create a new PHP file (e.g.,
server.php
) with the following content:<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; $worker = new Worker("http://0.0.0.0:8080"); $worker->onMessage = function($connection, $request) { $connection->send("Hello, Workerman!"); }; Worker::runAll();
-
Run the server:
php server.php start
-
Access the server at
http://localhost:8080
in your web browser.
Competitor Comparisons
Event-driven, non-blocking I/O with PHP.
Pros of ReactPHP
- More comprehensive ecosystem with a wide range of components
- Better suited for complex, event-driven applications
- Stronger focus on asynchronous programming patterns
Cons of ReactPHP
- Steeper learning curve, especially for developers new to asynchronous programming
- Can be more complex to set up and configure for simple use cases
Code Comparison
ReactPHP:
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server('127.0.0.1:8080', $loop);
$socket->on('connection', function (React\Socket\ConnectionInterface $conn) {
$conn->write("Hello ReactPHP!\n");
});
$loop->run();
Workerman:
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:8080');
$worker->onConnect = function($connection) {
$connection->send("Hello Workerman!\n");
};
Worker::runAll();
Summary
ReactPHP offers a more comprehensive ecosystem for complex, event-driven applications but comes with a steeper learning curve. Workerman, on the other hand, provides a simpler approach that may be more suitable for straightforward use cases. The code comparison illustrates the different approaches to handling connections, with ReactPHP using an event loop and Workerman using a more traditional worker model.
A non-blocking concurrency framework for PHP applications. 🐘
Pros of amp
- Built on top of PHP's native event loop, providing better integration with PHP's core functionality
- Offers a more comprehensive ecosystem with additional libraries for HTTP, WebSockets, and more
- Provides a more modern and flexible API design, making it easier to write asynchronous code
Cons of amp
- Steeper learning curve due to its more complex architecture and concepts
- Smaller community and fewer resources compared to Workerman
- May have slightly higher overhead in some scenarios due to its abstraction layers
Code Comparison
amp:
Loop::run(function () {
$server = Socket\listen("0.0.0.0:1337");
while ($socket = yield $server->accept()) {
$client = new Client($socket);
$client->onData(function ($data) use ($client) {
$client->write("Hello " . $data);
});
}
});
Workerman:
$worker = new Worker("tcp://0.0.0.0:1337");
$worker->onMessage = function($connection, $data) {
$connection->send("Hello " . $data);
};
Worker::runAll();
Both examples demonstrate a simple TCP server, but amp uses a more explicit asynchronous approach with generators and yields, while Workerman provides a more straightforward event-driven API.
🚀 Coroutine-based concurrency library for PHP
Pros of Swoole
- Higher performance due to its C-based implementation and asynchronous I/O
- Built-in support for WebSocket, HTTP/2, and TCP/UDP protocols
- Offers coroutine-based concurrency for easier asynchronous programming
Cons of Swoole
- Requires PHP extension installation, which can be complex on some systems
- Steeper learning curve due to its more advanced features and concepts
- Less compatible with traditional PHP applications and frameworks
Code Comparison
Workerman example:
use Workerman\Worker;
$worker = new Worker('websocket://0.0.0.0:2345');
$worker->onMessage = function($connection, $data) {
$connection->send('Hello ' . $data);
};
Worker::runAll();
Swoole example:
$server = new Swoole\WebSocket\Server('0.0.0.0', 9501);
$server->on('message', function ($server, $frame) {
$server->push($frame->fd, 'Hello ' . $frame->data);
});
$server->start();
Both examples demonstrate a simple WebSocket server, but Swoole's implementation is more concise and leverages its built-in WebSocket support. Workerman's approach is more traditional and easier to understand for PHP developers new to asynchronous programming.
Cross-platform asynchronous I/O
Pros of libuv
- Cross-platform support for asynchronous I/O
- Widely used and battle-tested in major projects like Node.js
- Lower-level API offering more fine-grained control
Cons of libuv
- Steeper learning curve due to its C-based API
- Requires more boilerplate code for basic operations
- Less abstraction, which can lead to more complex code for simple tasks
Code Comparison
libuv (C):
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
uv_tcp_t server;
uv_tcp_init(loop, &server);
uv_run(loop, UV_RUN_DEFAULT);
Workerman (PHP):
use Workerman\Worker;
$worker = new Worker('tcp://0.0.0.0:8080');
$worker->onMessage = function($connection, $data) {
$connection->send('Hello');
};
Worker::runAll();
Key Differences
- libuv is a C library, while Workerman is PHP-based
- libuv provides lower-level control, Workerman offers higher-level abstractions
- Workerman is specifically designed for PHP network programming, while libuv is language-agnostic and used in various projects
- libuv requires manual memory management, whereas Workerman leverages PHP's garbage collection
Both libraries serve different purposes and target different developer audiences, making direct comparison challenging in some aspects.
Node.js JavaScript runtime ✨🐢🚀✨
Pros of Node.js
- Larger ecosystem with more packages and libraries available
- Better performance for I/O-intensive operations due to its event-driven, non-blocking architecture
- More extensive documentation and community support
Cons of Node.js
- Higher memory usage compared to Workerman
- Steeper learning curve for developers new to asynchronous programming
- Less efficient for CPU-bound tasks due to its single-threaded nature
Code Comparison
Node.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
});
server.listen(8080);
Workerman:
use Workerman\Worker;
$http_worker = new Worker("http://0.0.0.0:8080");
$http_worker->onMessage = function($connection, $data) {
$connection->send('Hello World');
};
Worker::runAll();
Both examples create a simple HTTP server listening on port 8080 and responding with "Hello World". Node.js uses its built-in http
module, while Workerman uses its Worker
class. The Node.js version is more concise, but Workerman's approach may be more intuitive for PHP developers.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Workerman
What is it
Workerman is an asynchronous event-driven PHP framework with high performance to build fast and scalable network applications. Workerman supports HTTP, Websocket, SSL and other custom protocols. Workerman supports event extension.
Requires
A POSIX compatible operating system (Linux, OSX, BSD)
POSIX and PCNTL extensions required
Event extension recommended for better performance
Installation
composer require workerman/workerman
Documentation
Basic Usage
A websocket server
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// Create a Websocket server
$ws_worker = new Worker('websocket://0.0.0.0:2346');
// Emitted when new connection come
$ws_worker->onConnect = function ($connection) {
echo "New connection\n";
};
// Emitted when data received
$ws_worker->onMessage = function ($connection, $data) {
// Send hello $data
$connection->send('Hello ' . $data);
};
// Emitted when connection closed
$ws_worker->onClose = function ($connection) {
echo "Connection closed\n";
};
// Run worker
Worker::runAll();
An http server
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// #### http worker ####
$http_worker = new Worker('http://0.0.0.0:2345');
// 4 processes
$http_worker->count = 4;
// Emitted when data received
$http_worker->onMessage = function ($connection, $request) {
//$request->get();
//$request->post();
//$request->header();
//$request->cookie();
//$request->session();
//$request->uri();
//$request->path();
//$request->method();
// Send data to client
$connection->send("Hello World");
};
// Run all workers
Worker::runAll();
A tcp server
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// #### create socket and listen 1234 port ####
$tcp_worker = new Worker('tcp://0.0.0.0:1234');
// 4 processes
$tcp_worker->count = 4;
// Emitted when new connection come
$tcp_worker->onConnect = function ($connection) {
echo "New Connection\n";
};
// Emitted when data received
$tcp_worker->onMessage = function ($connection, $data) {
// Send data to client
$connection->send("Hello $data \n");
};
// Emitted when connection is closed
$tcp_worker->onClose = function ($connection) {
echo "Connection closed\n";
};
Worker::runAll();
Enable SSL
<?php
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// SSL context.
$context = [
'ssl' => [
'local_cert' => '/your/path/of/server.pem',
'local_pk' => '/your/path/of/server.key',
'verify_peer' => false,
]
];
// Create a Websocket server with ssl context.
$ws_worker = new Worker('websocket://0.0.0.0:2346', $context);
// Enable SSL. WebSocket+SSL means that Secure WebSocket (wss://).
// The similar approaches for Https etc.
$ws_worker->transport = 'ssl';
$ws_worker->onMessage = function ($connection, $data) {
// Send hello $data
$connection->send('Hello ' . $data);
};
Worker::runAll();
Custom protocol
Protocols/MyTextProtocol.php
namespace Protocols;
/**
* User defined protocol
* Format Text+"\n"
*/
class MyTextProtocol
{
public static function input($recv_buffer)
{
// Find the position of the first occurrence of "\n"
$pos = strpos($recv_buffer, "\n");
// Not a complete package. Return 0 because the length of package can not be calculated
if ($pos === false) {
return 0;
}
// Return length of the package
return $pos + 1;
}
public static function decode($recv_buffer)
{
return trim($recv_buffer);
}
public static function encode($data)
{
return $data . "\n";
}
}
use Workerman\Worker;
require_once __DIR__ . '/vendor/autoload.php';
// #### MyTextProtocol worker ####
$text_worker = new Worker('MyTextProtocol://0.0.0.0:5678');
$text_worker->onConnect = function ($connection) {
echo "New connection\n";
};
$text_worker->onMessage = function ($connection, $data) {
// Send data to client
$connection->send("Hello world\n");
};
$text_worker->onClose = function ($connection) {
echo "Connection closed\n";
};
// Run all workers
Worker::runAll();
Timer
use Workerman\Worker;
use Workerman\Timer;
require_once __DIR__ . '/vendor/autoload.php';
$task = new Worker();
$task->onWorkerStart = function ($task) {
// 2.5 seconds
$time_interval = 2.5;
$timer_id = Timer::add($time_interval, function () {
echo "Timer run\n";
});
};
// Run all workers
Worker::runAll();
AsyncTcpConnection (tcp/ws/text/frame etc...)
use Workerman\Worker;
use Workerman\Connection\AsyncTcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
$worker = new Worker();
$worker->onWorkerStart = function () {
// Websocket protocol for client.
$ws_connection = new AsyncTcpConnection('ws://echo.websocket.org:80');
$ws_connection->onConnect = function ($connection) {
$connection->send('Hello');
};
$ws_connection->onMessage = function ($connection, $data) {
echo "Recv: $data\n";
};
$ws_connection->onError = function ($connection, $code, $msg) {
echo "Error: $msg\n";
};
$ws_connection->onClose = function ($connection) {
echo "Connection closed\n";
};
$ws_connection->connect();
};
Worker::runAll();
Use HTTP proxy
<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Connection\AsyncTcpConnection;
$worker = new \Workerman\Worker();
$worker->onWorkerStart = function($worker){
echo 'å¼å§é¾æ¥' . PHP_EOL;
$url = 'ws://stream.binance.com:9443/ws';
$con = new AsyncTcpConnection($url);
$con->transport = 'ssl';
// $con->proxySocks5 = '127.0.0.1:1080';
$con->proxyHttp = '127.0.0.1:25378';
$con->onConnect = function(AsyncTcpConnection $con) {
$ww = [
'id' => 1,
'method' => 'SUBSCRIBE',
'params' => [
"btcusdt@aggTrade",
"btcusdt@depth"
]
];
echo 'é¾æ¥æå';
$con->send(json_encode($ww));
echo 'ok';
};
$con->onMessage = function(AsyncTcpConnection $con, $data) {
echo $data;
};
$con->onClose = function (AsyncTcpConnection $con) {
echo 'onClose' . PHP_EOL;
};
$con->onError = function (AsyncTcpConnection $con, $code, $msg) {
echo "error [ $code ] $msg\n";
};
$con->connect();
};
\Workerman\Worker::runAll();
Use Socks5 proxy
<?php
require __DIR__ . '/vendor/autoload.php';
use Workerman\Connection\AsyncTcpConnection;
$worker = new \Workerman\Worker();
$worker->onWorkerStart = function($worker){
echo 'å¼å§é¾æ¥' . PHP_EOL;
$url = 'ws://stream.binance.com:9443/ws';
$con = new AsyncTcpConnection($url);
$con->transport = 'ssl';
$con->proxySocks5 = '127.0.0.1:1080';
// $con->proxyHttp = '127.0.0.1:25378';
$con->onConnect = function(AsyncTcpConnection $con) {
$ww = [
'id' => 1,
'method' => 'SUBSCRIBE',
'params' => [
"btcusdt@aggTrade",
"btcusdt@depth"
]
];
echo 'é¾æ¥æå';
$con->send(json_encode($ww));
echo 'ok';
};
$con->onMessage = function(AsyncTcpConnection $con, $data) {
echo $data;
};
$con->onClose = function (AsyncTcpConnection $con) {
echo 'onClose' . PHP_EOL;
};
$con->onError = function (AsyncTcpConnection $con, $code, $msg) {
echo "error [ $code ] $msg\n";
};
$con->connect();
};
\Workerman\Worker::runAll();
proxy supports TLS1.3, no Sniproxy channel
Available commands
php start.php start
php start.php start -d
php start.php status
php start.php status -d
php start.php connections
php start.php stop
php start.php stop -g
php start.php restart
php start.php reload
php start.php reload -g
Benchmarks
https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext&l=zik073-1r
Other links with workerman
Donate
LICENSE
Workerman is released under the MIT license.
Top Related Projects
Event-driven, non-blocking I/O with PHP.
A non-blocking concurrency framework for PHP applications. 🐘
🚀 Coroutine-based concurrency library for PHP
Cross-platform asynchronous I/O
Node.js JavaScript runtime ✨🐢🚀✨
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot