Home >PHP Framework >Swoole >Swoole Advanced: Using Coroutines to Write Concurrent Servers

Swoole Advanced: Using Coroutines to Write Concurrent Servers

WBOY
WBOYOriginal
2023-06-14 23:39:12778browse

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:

  1. Define the protocol format

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.

  1. Define business processing

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!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn