Swoole Server对象

Swoole允许通过PHP构建一个全新的Server,用于创建一个异步服务器程序,监听请求并做出响应。

  • 支持TCP、UDP、UnixSocket三种协议
  • 支持IPv4、IPv6
  • 支持SSL/TLS单向双向证书的隧道加密

使用注意

  • Swoole Server是一个独立的服务,只能用于php-cli环境,在其他环境下会抛出致命错误。
  • 不要在Swoole Server创建之前调用其它异步IO的API,否则将会创建失败。

运行流程

  1. 构建Server对象
  2. 设置运行时参数
  3. 注册事件回调函数
  4. 启动服务器
4933701-dd915e1d21c87e6b.png
Swoole运行流程

构建Server对象

原型

swoole_server(string $host, int $port = 0, int $mode = SWOOLE_PROCESS,  int $socket_type = SWOOLE_SOCK_TCP)

参数

  • string $host 服务器主机地址
  • int $port 服务器端口号
  • int $mode 服务器运行模式,支持SWOOLE_PROCESS默认多进程模式、SWOOLE_BASE单线程模式
  • int $socket_type 套接字类型,支持TCPUDPUDP6UnixSocketStream/Dgram六种
$serv = new Swoole\Server("0.0.0.0", 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP);

服务器主机地址string $host

Server的创建需要绑定监听的IP地址和端口,如果IP地址指定为127.0.0.1表示客户端只能位于本机才能连接,其它计算机将无法连接。如果需要所有客户端都能连接则需要设置为0.0.0.0

服务器主机端口int $port

端口号的取值范围是[1, 655353],一般1000以下的端口都会被常用服务所占用。

Server绑定端口号时需要注意端口号是否已经被占用,如果端口被占用需要更改为其它端口。

查看端口是否被占用

$ ss -lntpd | grep :22
tcp    LISTEN     0      0                      *:22                    *:*
tcp    LISTEN     0      0                     :::22                   :::*
tcp    LISTEN     0      0                      *:22                    *:*
tcp    LISTEN     0      0                     :::22                   :::*
$ netstat -tnlp | grep :22
netstat: showing only processes with your user ID
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 :::22                   :::*                    LISTEN      -

将某个服务通过某个端口对外提供服务的行为称为监听。例如Apache监听本机80端口,如果客户端通过80端口发送请求过来,操作系统会将请求转交给Apache,Apache就可以根据请求的具体内容进行处理并做出响应。

服务器运行模式 int $mode

多线程模式

多线程Worker模式中Reactor线程用来处理网络事件循环并读取数据,得到的请求会交给Worker线程去处理。当一个线程发生内存错误时整个进程会全部结束。由于PHP的ZenVM虚拟机在多线程模式下存在内存错误,多线程模式在Swoole1.6.0版本以后就关闭了。

多进程模式 SWOOLE_PROCESS

多进程模式用于大量的进程间通信、进程管理机制。适合业务逻辑非常复杂的场景,Swoole提供了完善的进程管理、内存保护机制,在业务逻辑非常复杂的情况下可以长期稳定的运行。

Swoole在Reactor线程中提供了Buffer功能,可以应对大量慢速连接和逐字节的恶意客户端。另外提供了CPU亲和设置选项,使程序运行效率更佳。

多进程模式的优点

  • 连接与数据请求发送是分离的,不会因为某些连接数据量大或某些连接数据量小而导致Worker进程不均衡。
  • Worker进程发送致命错误时连接并不会被切断
  • 可实现单连接并发,仅保持少量TCP连接,请求可并发地在多个Worker进程中处理。

多进程模式的缺点

  • 存在2次IPC开销,Master进程与Worker进程需要使用UnixSocket进行通信。
  • 不支持某些高级功能,如sendwaitpauseresume等操作。
4933701-2eadd4f658c27f89.png
Swoole Process模式结构

多线程模式操作流程

注意:不考虑TaskWorker进程的情况下

  1. Master进程fork创建Manager进程
  2. Master进程pthread_create创建Reactor线程
    注意这里的顺序,Master进程不能先pthread_create创建Reactor线程然后再fork创建Manager进程,因为fork时只能复制一个线程。
  3. Manager进程fork创建Worker进程
    Master进程fork创建的Manager进程、Manager进程fork创建的Worker进程,都会继承Master中已经打开的文件描述符。
  4. Master进程先创建多个套接字对,用于和Worker进程通信。

多进程模式请求处理流程

4933701-ab3354612ae8e565.png
多进程模式请求处理流程

Swoole的Master进程与Worker进程之间的通信流程

  1. Master进程创建N个套接字对
  2. Master进程fork创建Manager管理进程
  3. Manager进程fork创建Worker进程
  4. Master进程与Worker进程都有sv[1] - sv[2n+2]2n+2个文件描述符,也就是fork出的子进程会自动继承父进程的文件描述符。
  5. Master进程会与Worker进程进行通信,Worker进程之间不会相互通信。
单线程模式SWOOLE_BASE

单线程模式是传统的异步非阻塞Server,与Nginx和Node.js等程序完全是一致的。单线程模式中会在事件循环中直接调用PHP的函数,而不是使用dispatch投递任务。如果回调函数中有阻塞操作会导致Server退化为同步模式。单线程模式下worker_num配置参数仍然有效,它会启动多个Worker进程。

单线程模式的特点

  • 单线程模式下没有Master进程的角色
  • 每个Worker进程同时承担了Process模式下Reactor线程和Worker进程两部分职责
  • 单线程模式下Manager进程是可选的,当设置了worker_num=1且没有使用Task和MaxRequest特性时,底层将会直接创建一个单独的Worker进程,而不会创建Manager进程。

单线程模式的优点

  • 没有IPC开销性能更好
  • 代码更简单不容易出错

单线程模式的缺点

  • TCP连接是在Worker进程中维持的
    当某个Worker进程挂掉时此Worker内的所有连接都将被关闭
  • 少量TCP长连接无法利用到所有Worker进程
  • TCP连接与Worker是绑定的
    长连接应用中某些连接的数量大,这些连接所在的Worker进程负载会非常高,但是某些连接数据量小时。某些连接数量小时所在的Worker进程的负载会非常低,不同的Worker进程无法实现均衡。

单线程模式适用场景

如果客户端连接之间不需要交互,可以使用单线程模式,如Memcache、HTTP服务器等。

例如:

服务器

$ vim server.php
<?php
class Server
{
    private $server;

    public function __construct($host = "0.0.0.0", $port = 9501, $configs = [])
    {
        //创建服务器对象
        $this->server = new swoole_server($host, $port);
        //设置服务器运行时参数
        $this->server->set($configs);
        //注册监听函数
        $this->server->on("Start", [$this, "onStart"]);
        $this->server->on("Connect", [$this, "onConnect"]);
        $this->server->on("Receive", [$this, "onReceive"]);
        $this->server->on("Close", [$this, "onClose"]);
        $this->server->on("Task", [$this, "onTask"]);
        $this->server->on("Finish", [$this, "onFinish"]);
        //启动服务器
        $this->server->start();
    }
    public function onStart(swoole_server $server)
    {

        $version = SWOOLE_VERSION;
        $master_pid = $server->master_pid;
        $manager_pid = $server->manager_pid;
        echo "[start] version:{$version} master:{$master_pid} manager:{$manager_pid}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
    }
    public function onConnect(swoole_server $server, $fd, $reactor_id)
    {
        echo "[connect] reactor:{$reactor_id} client:{$fd}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
    }
    public function onReceive(swoole_server $server, $fd, $reactor_id, $data)
    {
        echo PHP_EOL."[receive] reactor:{$reactor_id} client:{$fd} data:{$data}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
        //send a task to task worker process
        $param = [];
        $param["fd"] = $fd;
        //start a task
        $message = json_encode($param);
        $server->task($message);
        echo "[receive] continue handle worker".PHP_EOL;
    }
    public function onClose(swoole_server $server, $fd)
    {
        echo "[close] client:{$fd}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
    }
    public function onTask(swoole_server $server, $task_id, $reactor_id, $data)
    {
        echo "[task] task:{$task_id} reactor:{$reactor_id} data:{$data}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
        for($i=0; $i<3; $i++){
            sleep(1);
            echo "[task] task {$task_id} handle {$i} times...".PHP_EOL;
        }

        $param = json_decode($data, true);
        $fd = $param["fd"];

        $message = "task {$task_id} success";
        $server->send($fd, $message);

        return "task {$task_id} finished";
    }
    public function onFinish(swoole_server $server, $task_id, $data)
    {
        echo "[finish] task:{$task_id} data:{$data}".PHP_EOL;
        echo json_encode($server).PHP_EOL;
    }
}

$host = "0.0.0.0";
$port = 9501;
$configs = [];
$configs["worker_num"] = 8;
$configs["task_worker_num"] = 8;
$configs["daemonize"] = false;
$configs["max_request"] = 1000;
$configs["log_file"] = "./swoole.log";
$server = new Server($host, $port, $configs);

客户端

$ vim client.php
<?php
class Client
{
    private $client;

    public function __construct($host, $port, $timeout=1)
    {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
        
        $this->client->on("Connect", [$this, "onConnect"]);
        $this->client->on("Receive", [$this, "onReceive"]);
        $this->client->on("Close", [$this, "onClose"]);
        $this->client->on("Error", [$this, "onError"]);

        if(!$this->isConnected()){
            $this->connect($host, $port, $timeout);
        }
    }
    public function isConnected()
    {
        return $this->client->isConnected();
    }
    public function connect($host, $port, $timeout)
    {
        $fp = $this->client->connect($host, $port, $timeout);
        if(!$fp)
        {
            echo "[connect] errno:{$fp->errCode} errmsg:{$fp->errMsg}".PHP_EOL;
            return;
        }
    }
    public function send($message)
    {
        $this->client->send($message);
    }
    public function onConnect(swoole_client $client)
    {
        fwrite(STDOUT, "send: ");
        swoole_event_add(STDIN, function(){
            fwrite(STDOUT, "send: ");
            $msg = trim(fgets(STDIN));
            $this->send($msg);
        });
    }

    public function onClose(swoole_client $client)
    {
        echo "[close]".PHP_EOL;
    }

    public function onReceive(swoole_client $client, $data)
    {
        echo "[receive] {$data}".PHP_EOL;
    }
    public function onError(swoole_client $client)
    {
        echo "[error]".PHP_EOL;
    }
}
$host = "127.0.0.1";
$port = 9501;
$timeout = 1;
$client = new Client($host, $port, $timeout);

运行服务器

$ php server.php
[start] version:4.3.2-alpha master:264 manager:265

查看当前服务器对象的值

{
    "setting": {
        "worker_num": 8,
        "task_worker_num": 8,
        "daemonize": false,
        "max_request": 1000,
        "log_file": "./swoole.log",
        "buffer_output_size": 2097152,
        "max_connection": 100000
    },
    "connections": {},
    "host": "0.0.0.0",
    "port": 9501,
    "type": 1,
    "mode": 2,
    "ports": [
        {
            "host": "0.0.0.0",
            "port": 9501,
            "type": 1,
            "sock": 4,
            "setting": {
                "worker_num": 8,
                "task_worker_num": 8,
                "daemonize": false,
                "max_request": 1000,
                "log_file": "./swoole.log"
            },
            "connections": {}
        }
    ],
    "master_pid": 264,
    "manager_pid": 265,
    "worker_id": -1,
    "taskworker": false,
    "worker_pid": 0
}

运行客户端

$ php client.php
send:

此时客户端处于输入等待状态,此时在查看服务端打印输入信息为

$ php server.php
[start] version:4.3.2-alpha master:264 manager:265
[connect] reactor:0 client:1

此时服务器对象与之前的区别

{
    "setting": {
        "worker_num": 8,
        "task_worker_num": 8,
        "daemonize": false,
        "max_request": 1000,
        "log_file": "./swoole.log",
        "buffer_output_size": 2097152,
        "max_connection": 100000
    },
    "connections": {},
    "host": "0.0.0.0",
    "port": 9501,
    "type": 1,
    "mode": 2,
    "ports": [
        {
            "host": "0.0.0.0",
            "port": 9501,
            "type": 1,
            "sock": 4,
            "setting": {
                "worker_num": 8,
                "task_worker_num": 8,
                "daemonize": false,
                "max_request": 1000,
                "log_file": "./swoole.log"
            },
            "connections": {}
        }
    ],
    "master_pid": 264,
    "manager_pid": 265,
    "worker_id": 1,
    "taskworker": false,
    "worker_pid": 276
}

对比发现,当前的服务器对象中

"worker_id": 1,
"worker_pid": 276

客户端向服务端发送消息

$ php client.php
send: hello
send:

观察服务器对象的变化

$ php server.php
[start] version:4.3.2-alpha master:264 manager:265
{"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log","buffer_output_size":2097152,"max_connection":100000},"connections":{},"host":"0.0.0.0","port":9501,"type":1,"mode":2,"ports":[{"host":"0.0.0.0","port":9501,"type":1,"sock":4,"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log"},"connections":{}}],"master_pid":264,"manager_pid":265,"worker_id":-1,"taskworker":false,"worker_pid":0}
[connect] reactor:0 client:1
{"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log","buffer_output_size":2097152,"max_connection":100000},"connections":{},"host":"0.0.0.0","port":9501,"type":1,"mode":2,"ports":[{"host":"0.0.0.0","port":9501,"type":1,"sock":4,"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log"},"connections":{}}],"master_pid":264,"manager_pid":265,"worker_id":1,"taskworker":false,"worker_pid":276}

[receive] reactor:0 client:1 data:hello
{"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log","buffer_output_size":2097152,"max_connection":100000},"connections":{},"host":"0.0.0.0","port":9501,"type":1,"mode":2,"ports":[{"host":"0.0.0.0","port":9501,"type":1,"sock":4,"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log"},"connections":{}}],"master_pid":264,"manager_pid":265,"worker_id":1,"taskworker":false,"worker_pid":276}
[receive] continue handle worker
[task] task:0 reactor:1 data:{"fd":1}
{"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log","buffer_output_size":2097152,"max_connection":100000},"connections":{},"host":"0.0.0.0","port":9501,"type":1,"mode":2,"ports":[{"host":"0.0.0.0","port":9501,"type":1,"sock":4,"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log"},"connections":{}}],"master_pid":264,"manager_pid":265,"worker_id":8,"taskworker":true,"worker_pid":267}
[task] task 0 handle 0 times...
[task] task 0 handle 1 times...
[task] task 0 handle 2 times...
[finish] task:0 data:task 0 finished
{"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log","buffer_output_size":2097152,"max_connection":100000},"connections":{},"host":"0.0.0.0","port":9501,"type":1,"mode":2,"ports":[{"host":"0.0.0.0","port":9501,"type":1,"sock":4,"setting":{"worker_num":8,"task_worker_num":8,"daemonize":false,"max_request":1000,"log_file":".\/swoole.log"},"connections":{}}],"master_pid":264,"manager_pid":265,"worker_id":1,"taskworker":false,"worker_pid":276}

未完待续...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Swoole是一个高性能的PHP网络通信框架,而PostgreSQL是一种强大的关系型数据库管理系统。它们可以结合使用来构建高性能的Web应用程序。 使用Swoole连接PostgreSQL需要使用PHP扩展包,例如swoole_postgresql。你需要在服务器上安装并启用此扩展包。然后,您可以使用Swoole提供的异步客户端来连接到PostgreSQL服务器,并执行查询和其他数据库操作。 以下是一个使用Swoole连接PostgreSQL的示例代码: ```php <?php $server = new Swoole\Coroutine\PostgreSQL(); $server->connect("host=127.0.0.1 port=5432 dbname=mydb user=myuser password=mypass"); $result = $server->query('SELECT * FROM mytable'); print_r($result); $server->close(); ?> ``` 这个例子中,我们首先创建了一个Swoole的PostgreSQL客户端对象,然后连接到PostgreSQL服务器。接下来,我们执行了一个简单的查询,并将结果打印到屏幕上。最后,我们关闭了数据库连接。 ### 回答2: Swoole PostgreSQL是一种基于Swoole扩展开发的PostgreSQL客户端库。PostgreSQL是一种强大的开源关系型数据库,它的特点包括高度的可扩展性、开放性和协议兼容性。Swoole PostgreSQL扩展允许开发人员使用PHP语言轻松访问和操作PostgreSQL数据库。 使用Swoole PostgreSQL有以下几个优势。首先,Swoole PostgreSQL基于Swoole扩展,可以充分利用Swoole的协程和异步特性,提高数据库访问的效率和性能。这意味着可以同时处理多个数据库操作请求,而不会阻塞其他进程或线程。 其次,Swoole PostgreSQL具有简单易用的接口,开发人员可以使用熟悉的PHP风格的语法来执行查询、插入、更新和删除操作。它还提供了一些高级功能,如预处理语句、事务管理和异步查询。 另外,Swoole PostgreSQL支持连接池管理,可以减少连接和断开连接的开销,提高数据库连接的复用率。这对于频繁的数据库访问非常有用,可以有效地减少资源消耗,并提高系统的稳定性和性能。 总而言之,Swoole PostgreSQL是一个功能强大、高效可靠的数据库访问库,它通过结合Swoole扩展的优势,提供了更好的数据库访问性能和开发体验。无论是构建高并发的Web应用程序、实时数据分析系统还是其他需要频繁访问数据库的应用场景,Swoole PostgreSQL都可以是一个很好的选择。 ### 回答3: Swoole是一个高性能的PHP扩展,它可以为PHP提供异步、并发、高性能的能力。而PostgreSQL则是一种功能强大的开源关系型数据库管理系统。 Swoole可以与PostgreSQL进行结合,实现异步操作数据库的目的。通过使用Swoole提供的协程技术,可以在PHP中实现非阻塞的数据库访问,提高系统的并发能力和响应速度。 在使用Swoole连接和操作PostgreSQL时,可以通过Swoole提供的协程MySQL客户端来建立与PostgreSQL的连接,并进行诸如查询数据、插入数据、更新数据等数据库操作。 与传统的PHP数据库访问不同,Swoole PostgreSQL使用异步操作,可以实现非阻塞式的数据库访问。这意味着,在查询数据库时,可以同时处理多个请求,提高系统的性能表现。 使用Swoole PostgreSQL还能够充分利用服务器的资源,通过同时处理多个数据库请求,减少了等待时间,提高了系统的效率。此外,Swoole还支持连接池的使用,提高了连接的复用率,减少了连接的创建和销毁开销,进一步提高了数据库访问的效率。 总结来说,Swoole PostgreSQL结合了Swoole的高性能特性和PostgreSQL的强大功能,提供了一种高效、异步、并发的数据库访问方式。这对于一些高并发、响应要求高的应用场景,具有很大的优势。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值