In high-concurrency network application scenarios, Swoole, as a long-range process communication framework, is increasingly favored by developers. Swoole provides a rich network programming API, allowing developers to use coroutines for asynchronous programming, improving concurrent processing capabilities. This article will introduce how to use Swoole and coroutines to write a simple concurrent server.
1. Environment setup
Before we start, we need to install the Swoole extension. For the installation method, please refer to the Swoole official documentation. This article uses PHP7.2 version.
2. Server program framework
We need to use Swoole’s TCP server. The specific implementation needs to consider the following aspects:
In network applications, it is usually necessary to define a standard data transmission format. In this example, we can use a custom protocol format, as shown below:
class MyProtocol { const HEADER_SIZE = 4; const MAX_PACKAGE_SIZE = 1024 * 1024; public static function encode($data) { $package = json_encode($data, JSON_UNESCAPED_UNICODE); return pack('N', strlen($package)) . $package; } public static function decode($buffer) { if(strlen($buffer) < self::HEADER_SIZE) { return false; } $length = unpack('N', substr($buffer, 0, self::HEADER_SIZE))[1]; if($length > self::MAX_PACKAGE_SIZE) { return false; } if(strlen($buffer) < self::HEADER_SIZE + $length) { return false; } $package = substr($buffer, self::HEADER_SIZE, $length); return json_decode($package, true); } }
The protocol format contains a 4-byte header to store the length of the data packet, and a JSON string representation The actual data. This format can support different message types and achieve transmission reliability and scalability.
Business logic processing is defined in the callback function of the Server class, as shown below:
class Server { private $serv; public function __construct() { $this->serv = new SwooleServer('0.0.0.0', 9501); $this->serv->set(array( 'worker_num' => 4, 'daemonize' => false, 'max_conn' => 10000, 'dispatch_mode' => 3, 'open_tcp_keepalive' => 1, 'tcp_keepidle' => 600, 'tcp_keepinterval' => 60, 'tcp_keepcount' => 5, )); $this->serv->on('Connect', array($this, 'onConnect')); $this->serv->on('Receive', array($this, 'onReceive')); $this->serv->on('Close', array($this, 'onClose')); $this->serv->start(); } public function onConnect($serv, $fd, $reactorId) { echo "Client: {$fd}-{$reactorId} Connect. "; } public function onReceive($serv, $fd, $reactorId, $data) { $message = MyProtocol::decode($data); if($message) { // Handle message & reply to client $this->serv->send($fd, MyProtocol::encode(array('status' => 0, 'message' => 'OK'))); } else { // Invalid message, close connection $this->serv->close($fd); } } public function onClose($serv, $fd, $reactorId) { echo "Client: {$fd}-{$reactorId} Close. "; } } new Server();
For each connection, the server needs Define three methods to handle operations such as connecting, accepting messages, closing connections, etc., and respond accordingly.
3. Using coroutines
Swoole provides a coroutine API to manage the control flow in asynchronous programming and provide a synchronous programming experience. Coroutine functions can be implemented through the coroutine series API. The following is the new code after using the coroutine, which uses the coroutine to handle asynchronous IO operations such as client connection and message reception:
class Server { private $serv; public function __construct() { $this->serv = new SwooleServer('0.0.0.0', 9501); $this->serv->set(array( 'worker_num' => 4, 'daemonize' => false, 'max_conn' => 10000, 'dispatch_mode' => 3, 'open_tcp_keepalive' => 1, 'tcp_keepidle' => 600, 'tcp_keepinterval' => 60, 'tcp_keepcount' => 5, )); $this->serv->on('Connect', array($this, 'onConnect')); $this->serv->on('Receive', array($this, 'onReceive')); $this->serv->on('Close', array($this, 'onClose')); $this->serv->start(); } public function onConnect($serv, $fd, $reactorId) { go(function() use($fd, $reactorId) { echo "Client: {$fd}-{$reactorId} Connect. "; }); } public function onReceive($serv, $fd, $reactorId, $data) { go(function() use($serv, $fd, $reactorId, $data) { $message = MyProtocol::decode($data); if($message) { // Handle message & reply to client $serv->send($fd, MyProtocol::encode(array('status' => 0, 'message' => 'OK'))); } else { // Invalid message, close connection $serv->close($fd); } }); } public function onClose($serv, $fd, $reactorId) { go(function() use($fd, $reactorId) { echo "Client: {$fd}-{$reactorId} Close. "; }); } } new Server();
Use go(function()) to add tasks to the coroutine for execution. The amount of code is reduced, while unnecessary callback functions and the cumbersome operation of manual management of control processes are avoided.
4. How to deploy
Through the command line tool provided by Swoole, we can simply manage the process of running the server. For example, we start a Swoole TCP server as follows:
php server.php
If you need to keep the server running in the background, you can set the daemonize option:
php server.php --daemonize
Use the command line tool provided by Swoole to open, restart and Stop the server and other operations:
swoole_server [start|stop|reload|restart|shutdown]
By using Swoole, we can easily implement efficient concurrent network applications. The Swoole TCP server written using coroutines not only simplifies the code structure, but also has higher performance. Compared with traditional multi-process or multi-thread servers, it can obtain better processing performance and significantly save the resource consumption of the server.
The above is the detailed content of Swoole Advanced: Using Coroutines to Write Concurrent Servers. For more information, please follow other related articles on the PHP Chinese website!