swoole 极简聊天室
原本我是准备接着写我那个多进程教程的,今天心血来潮想看看swoole的websocket, 我就点开了这个 WebSocket 我看了看官网的demo,觉得看起来很简单嘛,
<?php
//官网demo
$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
echo "server: handshake success with fd{$request->fd}\n";//$request->fd 是客户端id
});
$server->on('message', function (swoole_websocket_server $server, $frame) {
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");//$frame->fd 是客户端id,$frame->data是客户端发送的数据
//服务端向客户端发送数据是用 $server->push( '客户端id' , '内容')
});
$server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});
$server->start();
我就是喜欢这种简单易懂的demo ,每行代码意思一看就明白
服务端有了,我找点客户端的js代码 火狐的MDN
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<script type="text/javascript">
var exampleSocket = new WebSocket("ws://0.0.0.0:9501");
exampleSocket.onopen = function (event) {
exampleSocket.send("亲爱的服务器!我连上你啦!");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</script>
</head>
<body>
<input type="text" id="content">
<button onclick="exampleSocket.send( document.getElementById('content').value )">发送</button>
</body>
</html>
最后命令行运行php文件,之后浏览器打开html文件, F12打开调试界面看console,ok , 没有问题
这个时候我突然想到一个事情,因为我做多进程的那个教程里,在主进程中会将所有的子进程的句柄存起来,以后进行进程间通讯用。 那么 我将所有的客户端的链接存起来存成数组,每当一个客户端发送消息时,我就遍历这个客户端数组,将消息群发一遍,不久实现了聊天室了吗? 然后就,服务端代码成了这个样子
<?php
$map = array();//客户端集合
$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
global $map;//客户端集合
$map[$request->fd] = $request->fd;//首次连上时存起来
});
$server->on('message', function (swoole_websocket_server $server, $frame) {
global $map;//客户端集合
$data = $frame->data;
foreach($map as $fd){
$server->push($fd , $data);//循环广播
}
});
$server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});
$server->start();
哈哈 , 我觉得这样就大功告成了,结果发现自己是 图样图森破 大家可以自己试试,运行php后 , 浏览器打开两个页面,看看console.log的内容是什么
运行良好,可是并没有实现我们说的那种聊天效果。 找找原因吧。 我第一反映看看$map里面是什么,就输出看看,结果发现这个map里面只有一个元素。 唉,不对啊,我这是全局变量,难道不应该是有几个客户端链接,就有几个元素吗? 这是怎么回事啊,竟然没有保存到所有客户端id?
到了这一步,我解决不了map变量的这个问题了,然后我就想看看那个fd是什么东西, 老规矩 var_dump输出 , 发现fd就是 int类型的数字,并且是自增的 这好办了,不就是数字嘛
于是呼,我就这样做 变量存不了,我搞不定,我存文本里嘛。 最终版 websocket.php
<?php
$server = new swoole_websocket_server("0.0.0.0", 9501);
$server->on('open', function (swoole_websocket_server $server, $request) {
file_put_contents( __DIR__ .'/log.txt' , $request->fd);
});
$server->on('message', function (swoole_websocket_server $server, $frame) {
global $client;
$data = $frame->data;
$m = file_get_contents( __DIR__ .'/log.txt');
for ($i=1 ; $i<= $m ; $i++) {
echo PHP_EOL . ' i is ' . $i . ' data is '.$data . ' m = ' . $m;
$server->push($i, $data );
}
/*一直轮询
while(1){
echo '啊啊'.mt_rand(0,9999);
$serv->push($task_id, '用户'.mt_rand(0,9999));
//模拟慢速任务
sleep(5);
}
*/
});
$server->on('WorkerStart', function (swoole_websocket_server $server, $worker_id){
//每三秒发送后断开
Swoole\Timer::tick(3000, function (int $timer_id, $server) {
echo "timer_id #$timer_id, after 3000ms.\n";
$server->connections=[1,2,3,4,5];
foreach ($server->connections as $fd){
$rand = mt_rand(0,9999);
$server->push($fd, $rand);
$server->close($fd);//断开链接
}
}, $server);
});
$server->on('close', function ($ser, $fd) {
echo "client {$fd} closed\n";
});
$server->start();
再次打开html文件,多个页面进行输入观察,ok,可以了。
当然,作为聊天室,我这写的也过于简陋了,界面大家自己可以写的好看一些(因为我懒的写界面) 还有,每次的发送聊天的记录,应该存起来,这样,如果有新的连接连过来的时候,先把以前的聊天记录发过去,这样,我想体验更好一些
然后,大家可以愉快的聊天了。哈哈
猜你喜欢
Laravel验证码
阅读 1187Composer生成Laravel验证码
基于 Swoole 实现简单的 WebSocket 服务器及客户端
阅读 1933基于 Swoole 实现简单的 WebSocket 服务器及客户端
Laravel邮箱推送
阅读 2602Laravel发送邮件
Layui富文本视频等多功能
阅读 1112Layui富文本多功能添加
Resultful API规范
阅读 1290什么是resultful
抖音接入
阅读 2768PHP 接入抖音开放平台
LaravelS基于Swoole实现高性能 HTTP 服务器
阅读 2323LaravelS基于Swoole 配置nginx等
Git使用
阅读 1100Git基本配置/服务器搭建仓库