当前位置: 首页 > 后端技术 > PHP

Swoole4.x探索多进程TCP协程服务实现

时间:2023-03-29 16:53:25 PHP

学习过Workman框架的同学会发现,其实workman的核心就是利用phpsocket扩展加上pcntl扩展实现其底层网络服务和Multi-进程调度。那么我们今天就来讨论一下如何使用Swoole的CoroutineSocket模块来实现我们自己的tcp服务。先写个小测试代码,test.php代码如下$socket=newCo\Socket(AF_INET,SOCK_STREAM,0);$socket->bind('127.0.0.1',9601);$socket->listen(128);go(function()use($socket){while(true){$client=$socket->accept(-1);$data=$client->recv(64,10);var_dump('Recv:'.$data);$client->sendAll('replyat'.time());$client->close();}});我们执行phptest.php,创建一个cmd控制台,使用telnet模拟tcp客户端,可以看到如下结果:telnet127.0.0.19601Trying127.0.0.1...Connectedtolocalhost.Escapecharacteris'^]'。asdreplyat1559713416Connectionclosedbyforeignhost以上说明我们已经成功建立了一个简单的TCP服务器。而且细心的同学会发现,如果我在上面的代码中recv之后有一些数据库行为,那么我的TCP服务器只能同时接受和处理一个连接,并发度接近于1。所以我们可以做一个小小的改进,如下:$socket=newCo\Socket(AF_INET,SOCK_STREAM,0);$socket->bind('127.0.0.1',9601);$socket->listen(128);go(function()use($socket){while(true){$client=$socket->accept(-1);go(function()use($client){$data=$client->recv(64,10);var_dump('Recv:'.$data);//模拟数据库耗时,假设我们的数据库也使用协程api\co::sleep(1);$client->sendAll('replyat'.time());$client->close();});}});我们使用协程将connectionaccept之后的所有逻辑放到另一个子协程中去处理,这样我们的TCPserver就可以继续acceptconnections,提高了我们的并发能力。但是,在实际编程中,我们不可能做到100%完整的协程API,而且我的机器也是多核处理器,那么此时如何才能尽可能的使用我的CPU呢?因此,我们可以利用端口复用特性和Swoole的Process来搭建一个多进程的TCP协程服务器。引入Process是因为在本章中,SwooleProcess的封装不是我们关心的,所以这里直接使用EasySwoole封装的process组件。composer需要easyswoole/component来实现我的ProcessClass,代码如下useCo\Socket;useEasySwoole\Component\Process\AbstractProcess;classServerextendsAbstractProcess{protectedfunctionrun($arg){$socket=newSocket(AF_INET,SOCK_STREAM,0);//这里的关键是允许重用$socket->setOption(SOL_SOCKET,SO_REUSEPORT,true);$socket->setOption(SOL_SOCKET,SO_REUSEADDR,true);$socket->bind('127.0.0.1',9601);$套接字->听(128);go(function()use($socket){while(true){$client=$socket->accept(-1);go(function()use($client){$data=$client->recv(64,10);var_dump('Recv:'.$data);//模拟数据库耗时,假设我们的数据库也使用协程api\co::sleep(1);$client->sendAll('replyat'.time());$client->close();});}});}}在上面的代码中,我们添加了允许端口复用的选项,否则在多进程模式下,会导致监听失败。我们在cli模式下测试了五个进程($i=1;$i<5;$i++){$p=newServer("TcpServer.{$i}");$p->getProcess()->start();}//主进程等待回收while($ret=\Swoole\Process::wait()){echo"PID={$ret['pid']}\n";}我们很简单的实现了一个多进程的TCP协程服务。总而言之,Swoole4.x的协程能力还是很强大的,可以让PHPer以最小的成本实现一个高性能的TCP服务,而不用学习一门新的语言,如果需要更完美的代码,可以参考http://easyswoole.com/本框架的项目代码,如果有喜欢的同学可以随意点个star,github地址https://github.com/easy-swool...