首页
下载
文档
社区
视频
捐赠
源代码
赞助商
AOT 编译器
AI 助理
商业产品
PHP AOT 原生编译器
Swoole-Compiler 代码加密器
CRMEB 新零售社交电商系统
登录
注册
全部
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
发表新帖
同时运行多个websocket协程客户端的关闭问题
### 问题描述 从redis中取出多个房间号来开启websocket-client进行监听 websocket客户端是从http客户端的协程池中取出后升级而成 监听开启后同时监听多个房间并获取数据 而后需要根据redis中的房间号对应的值来关闭监听 问题就是:当关闭其中某一个监听并归还连接时所有房间都停止了监听 ### Swoole版本,PHP版本,以及操作系统版本信息 swoole4.4.13 php7.2 centos7(windows下vagrantbox虚拟机) ### 相关代码 ```php <?php //http_client协程池 class Pool { protected static $instance; protected $channel; public static function i():self { return static::$instance ?? (static::$instance = new static()); } public function __construct(int $size = 10) { $this->channel = new Swoole\Coroutine\Channel($size); $host = 'www.test.com'; $port = 80; while($size--){ $cli = new Swoole\Coroutine\Http\Client($host,$port); if($cli){ $this->put($cli); }else{ throw new RuntimeException($cli->errCode); } } } public function put(Swoole\Coroutine\Http\Client $client): void { $this->channel->push($client); } public function get(float $timeout = -1): Swoole\Coroutine\Http\Client { return $this->channel->pop($timeout) ?: null; } public function close(Swoole\Coroutine\Http\Client $client) { $client->close(); $this->channel->close(); } } // Co\Run(function (){ $redis = new Swoole\Coroutine\Redis(); $redis->setOptions( [ 'connect_timeout' => 1, 'time_out' => 3, ] ); $redis->connect('127.0.0.1',6379); $redis->auth(123456); //取出所有房间 $key = 'rooms'; $roomids = $redis->hKeys($key); Pool::i(); foreach ($roomids as $roomid){ //过滤掉不用监听的房间 if($redis->hGet($key,$roomid) == 0){ continue; } go(function () use ($roomid,$redis){ //取出一个连接 $pool = Pool::i(); $cli = $pool->get(); //建立ws连接 $ret = $cli->upgrade('/'.$roomid); swoole_timer_tick(5000,function () use ($pool,$roomid,$redis,$cli){ //每5秒发送一次ping 保持心跳连接 $cli->push('ping'); //检测房间是否要停止监听 if($redis->hget('laravel_database_desire_tree_rooms',$roomid) == 0){ //归还连接 $pool->put($cli); //关闭连接 $pool->close($cli); //关闭其中一个后其他正在监听的连接都断掉了 无法获取数据 } }); if ($ret) { while(true) { //接收获取数据 if($recvData = $cli->recv()){ var_dump($data = json_decode($recvData->data)); } } } }); } }); ``` ### 你期待的结果是什么?实际看到的错误信息又是什么? 解决关闭其中某个websocket——client连接 而不影响其他的监听 希望有老师同学能帮忙指点一下 感谢!
发布于6年前 · 9 次浏览 · 来自
提问
j
jonic
### 问题描述 从redis中取出多个房间号来开启websocket-client进行监听 websocket客户端是从http客户端的协程池中取出后升级而成 监听开启后同时监听多个房间并获取数据 而后需要根据redis中的房间号对应的值来关闭监听 问题就是:当关闭其中某一个监听并归还连接时所有房间都停止了监听 ### Swoole版本,PHP版本,以及操作系统版本信息 swoole4.4.13 php7.2 centos7(windows下vagrantbox虚拟机) ### 相关代码 ```php <?php //http_client协程池 class Pool { protected static $instance; protected $channel; public static function i():self { return static::$instance ?? (static::$instance = new static()); } public function __construct(int $size = 10) { $this->channel = new Swoole\Coroutine\Channel($size); $host = 'www.test.com'; $port = 80; while($size--){ $cli = new Swoole\Coroutine\Http\Client($host,$port); if($cli){ $this->put($cli); }else{ throw new RuntimeException($cli->errCode); } } } public function put(Swoole\Coroutine\Http\Client $client): void { $this->channel->push($client); } public function get(float $timeout = -1): Swoole\Coroutine\Http\Client { return $this->channel->pop($timeout) ?: null; } public function close(Swoole\Coroutine\Http\Client $client) { $client->close(); $this->channel->close(); } } // Co\Run(function (){ $redis = new Swoole\Coroutine\Redis(); $redis->setOptions( [ 'connect_timeout' => 1, 'time_out' => 3, ] ); $redis->connect('127.0.0.1',6379); $redis->auth(123456); //取出所有房间 $key = 'rooms'; $roomids = $redis->hKeys($key); Pool::i(); foreach ($roomids as $roomid){ //过滤掉不用监听的房间 if($redis->hGet($key,$roomid) == 0){ continue; } go(function () use ($roomid,$redis){ //取出一个连接 $pool = Pool::i(); $cli = $pool->get(); //建立ws连接 $ret = $cli->upgrade('/'.$roomid); swoole_timer_tick(5000,function () use ($pool,$roomid,$redis,$cli){ //每5秒发送一次ping 保持心跳连接 $cli->push('ping'); //检测房间是否要停止监听 if($redis->hget('laravel_database_desire_tree_rooms',$roomid) == 0){ //归还连接 $pool->put($cli); //关闭连接 $pool->close($cli); //关闭其中一个后其他正在监听的连接都断掉了 无法获取数据 } }); if ($ret) { while(true) { //接收获取数据 if($recvData = $cli->recv()){ var_dump($data = json_decode($recvData->data)); } } } }); } }); ``` ### 你期待的结果是什么?实际看到的错误信息又是什么? 解决关闭其中某个websocket——client连接 而不影响其他的监听 希望有老师同学能帮忙指点一下 感谢!
赞
0
收藏
提问
分享
讨论
建议
公告
开发框架
CodeGalaxy
登录
后参与评论
评论
2020-06-02
Twosee
你这个pool的close实现就是错的, 你关连接就关连接, 为什么要把channel给close掉? 而且为了保持连接池内客户端的数量, 你关闭连接后还需要补充一个新的客户端进去
赞
0
回复
2020-06-02
j
jonic
回复
Twosee
老师您好 我把channel的close去掉了 还是一样的结果 请问还有哪里有问题的吗
赞
0
回复
2020-06-02
j
jonic
回复
Twosee
老师您好 我已把channel的关闭去掉了 还是出现所说的问题 还有哪里不对的地方吗
赞
0
回复
2020-06-02
Twosee
你这代码全都是问题, 你自己再捋捋吧, 太多了不可能全都给你指正 随便说几个 定时器tick以后也没有删除逻辑 协程开发不应该用定时器, 而是用协程写法类似于 `go(func(){ while (1) { sleep(x); if (stop) break; } })` 连接池pop方法失败返回null, 返回类型没有加`?` 一个redis连接一堆协程在用 redis就程序开始的时候循环读了一遍rooms, 有新的怎么办 越看越觉得这代码写的毫无逻辑
赞
0
回复
2020-06-02
j
jonic
回复
Twosee
感谢老师指点
赞
0
回复