我使用时的环境
Centos 7.9
PHP 7.4
Swoole 4.8.5
thinkPHP6 6.0.8
think-swoole 4.0
问题描述:socket.io与服务器连接成功,但是服务器没有根据客户端发的请求去执行,没有任何的返回,根本就没执行到listen中写的行为
网上的例子找了不少,其实网上也没几个,都试了一下,代码基本都是大同小异,但是我试的时候就是跑不起来,只要在config/swoole.php配置文件中开启了websocket,连接是成功的,但是就是没有返回,直到看到了这篇文章【think-swoole4.0.4 websocket 使用(追梦人)】,照着里面的例子,客户端终于能接收到数据了。我寻思着这是为啥呢?他的config/swoole.php中listen中的配置如下。
于是我照葫芦画瓢也复制了一条例子,在他下面新加了一条记录,结果又是不行?这我就emo了呀。加了交流群,但是没人鸟我,没办法了,只能翻他的源码了,一路从入口文件往下翻,终于在代码中发现了原因。在源码中只触发了swoole.websocket.Event的监听行为
文件位置:vendor/topthink/think-swoole/src/websocket/socketio/Handler.php
在他的源码中,当触发了onMessage事件时,它只触发了’swoole.websocket.Event’事件(这个事件名称为什么长成这样,跟config/swoole.php中不一样,是因为他在建立构建websocket服务的时候,会把在config/swoole.php中listen中写的参数转换成这样的形式。因为这个行为是依靠tp6中event来实现的,所以也可以直接在app/event.php中直接按照这样的形式写),不懂他为什么不写成通用的方式,现在这样写的话,,看他传入了$type(方法名),$data(客户端传递的参数)这些数据,就是说其实利用的就只是那一个监听行为,你自己在app\listener\WebsocketEvent.php中handler函数中去根据$type去判断要执行那个方法喽。只有一个监听行为,是不是可以不卡一些,然后运行的快一点??
我尝试着把此处的代码改成了这样,只要改成这样网上哪些例子就都能跑了,这样在config/swoole.php中配置的listen中填的那些行为。在客户端中触发哪个就走那个。
$result = $this->event->trigger('swoole.websocket.'.Str::studly($type), new WsEvent($type, $data));
不过我不建议这么改,因为我也不懂为什么不这样写,但是他现在的写法一定有道理,还是按他的来吧。而且改插件源码什么的,不合适!
代码
config\swoole.php
<?php
use think\swoole\websocket\socketio\Handler;
return [
'http' => [
'enable' => true,
'host' => '0.0.0.0',
'port' => 8998,
'worker_num' => swoole_cpu_num(),
'options' => [],
],
'websocket' => [
'enable' => true,
'handler' => Handler::class,
'ping_interval' => 25000,
'ping_timeout' => 60000,
'room' => [
'type' => 'table',
'table' => [
'room_rows' => 8192,
'room_size' => 2048,
'client_rows' => 4096,
'client_size' => 2048,
],
'redis' => [
'host' => '127.0.0.1',
'port' => 6379,
'max_active' => 3,
'max_wait_time' => 5,
],
],
'listen' => [
'event' => \app\listener\WebsocketEvent::class,
'test' => \app\listener\WebsocketTest::class
],
'subscribe' => [],
],
'rpc' => [
'server' => [
'enable' => false,
'host' => '0.0.0.0',
'port' => 9000,
'worker_num' => swoole_cpu_num(),
'services' => [],
],
'client' => [],
],
//队列
'queue' => [
'enable' => false,
'workers' => [],
],
'hot_update' => [
'enable' => env('APP_DEBUG', false),
'name' => ['*.php'],
'include' => [app_path()],
'exclude' => [],
],
//连接池
'pool' => [
'db' => [
'enable' => true,
'max_active' => 3,
'max_wait_time' => 5,
],
'cache' => [
'enable' => true,
'max_active' => 3,
'max_wait_time' => 5,
],
//自定义连接池
],
'tables' => [],
//每个worker里需要预加载以共用的实例
'concretes' => [],
//重置器
'resetters' => [],
//每次请求前需要清空的实例
'instances' => [],
//每次请求前需要重新执行的服务
'services' => [],
];
app\listener\WebsocketEvent.php
<?php
declare (strict_types = 1);
namespace app\listener;
use think\Container;
use think\swoole\Websocket;
class WebsocketEvent
{
public $websocket = null;
public function __construct(Container $container) {
$this->websocket = $container->make(Websocket::class);
}
/**
* 事件监听处理
*
* @return mixed
*/
public function handle($event)
{
echo "Event\n";
$func = $event->type; // 要调用的方法
if (!method_exists($this, $func)) {
$this->websocket->emit('testcallback', ['msg'=> $func.':方法不存在']);
} else {
$this->$func($event);
}
}
/**
* 测试类型
* @param $event
*/
public function test($event)
{
$this->websocket->emit('testcallback', ['aaaaa' => 1, 'getdata' => '123123']);
}
}
~
app\listener\WebsocketTest.php
<?php
declare (strict_types = 1);
namespace app\listener;
use think\Container;
use think\swoole\Websocket;
class WebsocketTest
{
public $websocket = null;
public function __construct(Container $container) {
$this->websocket = $container->make(Websocket::class);
}
/**
* 事件监听处理
*
* @return mixed
*/
public function handle($event)
{
$this->websocket->emit("testcallback", ['msg'=> '来自listen-test的数据返回']);
}
}
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.socket.io/socket.io-1.4.4.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
</head>
<body>
<div>
<div>
返回内容:
</div>
<div style="width: 600px;height: 600px" id="content">
</div>
</div>
<div>
在控制台中执行 socket.emit("test",{"asd":"我是内容"})
</div>
<div>
在控制台中执行 socket.emit("join",{"room":"roomtest"}) 加入房间
</div>
<div>
在控制台中执行 socket.emit("leave",{"room":["roomtest"]}) 离开房间
</div>
<script>
var socket = io('http://0.0.0.0:8998',{transports: ['websocket']});
//xxx.com 这个自己替换成自己的环境thinkphp-swoole 的端口或者是nginx的代理端口
//transports: ['websocket'] 一定要这个,改为websocket链接
//polling 这个不支持,轮询会导致请求变成http请求,post请求全部拒接掉
socket.emit('test',{"asd":"asd"});
//自定义msg事件,发送‘你好服务器’字符串向服务器
socket.on('testcallback',(data)=>{
//监听浏览器通过msg事件发送的信息
console.log('服务器返回的数据:', data);//你好浏览器
});
socket.emit('join',{"asd":"asd"});
socket.on('roomJoin',(data)=>{
console.log(data);//你好浏览器
})
</script>
</body>
</html>