swoole


swoole介绍

从swoole安装可以看出,它是php的一个扩展,对php的套接字编程做了大量的处理.

你可以使用swoole处理socket,常驻内存和协程的方式也提升了并发性能.

  • swoole扩展了php什么功能

在php-fpm解析器中,一次调度即为一次会话过程,内存会回收.

在php-cli中可以编写socket程序,即可常驻内存,也可以使用协程,所以swoole它扩展了php这一部分的功能.

关于协程这块,swoole支持类似go语言的协程,让phper也可以有一个后备选择,因此,用go完成php-cli的工作会是phper的方向.

安装swoole

--enable-swoole在swoole的官方文档写的很简洁,其实可以多提示两句的.

swoole不是php默认的扩展,是第三方扩展,加这个参数在php编译时是不能通过的.

将静态库编译进php,需要进入ext目录,然后下载第三库文件,重新生成php配置项.

静态编译到php中

wget https://down.pythonschool.com/php/php-8.0.8.tar.bz2
bzip2 -d php-8.0.8.tar.bz2
tar -xf php-8.0.8.tar
cd php-8.0.8
cd ext
wget https://down.pythonschool.com/php/swoole-src-4.7.0-dev.zip
unzip swoole-src-4.7.0-dev.zip
mv swoole-src swoole
cd ..
rm ./configure
./buildconf --force
./configure -h | grep swoole
yum -y install glibc-headers
yum -y install gcc-c++
./configure --enable-swoole
make
make install

以扩展方式编译

  • 在mac下安装,在安装4.7.0-src时,openssl会出错.
wget https://down.pythonschool.com/php/swoole-4.6.7.tgz
tar xf swoole-4.6.7.tgz
cd swoole-4.6.7
phpize
./configure --enable-http2 --enable-openssl --with-openssl-dir=/usr/local/opt/openssl@1.1
make
sudo make install
// 查看swoole是否开启openssl支持
php --ri swoole
Installing shared extensions:     /usr/lib/php/extensions/no-debug-non-zts-20180731/
Installing header files:          /usr/include/php/
  • 在centos下测试
wget https://down.pythonschool.com/php/swoole-src-4.7.0-dev.zip
unzip swoole-src-4.7.0-dev.zip
cd swoole-src
phpize
./configure
make
sudo make install
Installing shared extensions:     /usr/local/lib/php/extensions/no-debug-non-zts-20200930/
Installing header files:          /usr/local/include/php/

vim /usr/local/lib/php.ini

extension=swoole.so

添加代码提示工具

因为swoole不是php实现,只能安装一个类结构的文档.

composer require swoole/ide-helper

swoole调试

与xdebug不兼容,在php.ini中注释掉xdebug即可.

tcp服务器

// 创建tcp socket
$server = new Server('0.0.0.0', $this->port);
// 事件处理,连接
$server->on('Connect', function ($server, $fd) {
    // 输出客户端信息
    $clientInfo = $server->getClientInfo($fd);
    dump($clientInfo['remote_ip'].'@'.$clientInfo['remote_port']);
});
// 事件处理,接收,$reactor_id=>协程id,$data=>用户输入流
$server->on('Receive', function ($server, $fd, $reactor_id, $data) {
    $clientInfo = $server->getClientInfo($fd);
    $server->send($fd, sprintf("用户%s@%s,输入:%s", $clientInfo['remote_ip'], $clientInfo['remote_port'], $data));
});
// 事件处理,关闭
$server->on('Close', function ($server, $fd) {
    $clientInfo = $server->getClientInfo($fd);
    dump(sprintf("%s@%s:用户已退出", $clientInfo['remote_ip'], $clientInfo['remote_port']));
});
// 启动服务器
$server->start();
telnet 127.0.0.1 10000

udp服务器

// 创建udp socket
$server = new Server('0.0.0.0', $this->port, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
// 事件处理,接收
$server->on('Packet', function ($server, $data, $clientInfo) {
    dump($clientInfo);
    $server->sendto($clientInfo['address'], $clientInfo['port'], "Server:{$data}");
});
//启动服务器
$server->start();
netcat -u 127.0.0.1 10000

http服务器

// 创建http socket
$http = new \Swoole\Http\Server('0.0.0.0', $this->port);
// 事件处理,请求
$http->on('Request', function($request, $response){
    if ($request->server['path_info'] == '/favicon.ico') {
        $response->end();
        return;
    }
    $response->header('Content-Type', 'text/html; charset=utf-8');
    $response->end('<h1>Hello Moments</h1>');
    // 路由实现依赖$request->server['request_uri']
    dump($request,$response);
});
// 启动服务器
$http->start();
curl 127.0.0.1:10000

websocket服务器

// 创建websocket
$ws = new \Swoole\WebSocket\Server('0.0.0.0', $this->port);
// 事件处理,打开
$ws->on('Open', function ($ws, $request) {
    $ws->push($request->fd, "<h1>消息推送,打开!</h1>");
});
// 事件处理,消息
$ws->on('Message', function ($ws, $frame) {
    dump($frame->data);
    $ws->push($frame->fd, "<h1>已收到你的消息:{$frame->data}</h1>");
});
// 事件处理,关闭
$ws->on('Close', function ($ws, $fd) {
    $ws->push($fd, "<h1>消息推送,关闭!</h1>");
});
// 打开服务器
$ws->start();
var wsServer = 'ws://127.0.0.1:10000';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
    console.log("Connected to WebSocket server.");
};

websocket.onclose = function (evt) {
    console.log("Disconnected");
};

websocket.onmessage = function (evt) {
    console.log('Retrieved data from server: ' + evt.data);
};

websocket.onerror = function (evt, e) {
    console.log('Error occured: ' + evt.data);
};

php与swoole

php做socket用的是select/pool, 而swoole用epoll实现的Server性能更高.

关于协程这块

go语言关于协程这块味道更正宗一些.