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,可以了。
当然,作为聊天室,我这写的也过于简陋了,界面大家自己可以写的好看一些(因为我懒的写界面) 还有,每次的发送聊天的记录,应该存起来,这样,如果有新的连接连过来的时候,先把以前的聊天记录发过去,这样,我想体验更好一些
然后,大家可以愉快的聊天了。哈哈
猜你喜欢
Swoole 扩展安装与使用入门
阅读 2114Swoole从入门到实战
LaravelS基于Swoole实现高性能 HTTP 服务器
阅读 1984LaravelS基于Swoole 配置nginx等
Swoole 实现长连接
阅读 2800Swoole 实现长连接,心跳
基于 Swoole 实现简单的 WebSocket 服务器及客户端
阅读 1554基于 Swoole 实现简单的 WebSocket 服务器及客户端
PHP定时任务
阅读 1896PHP框架Laravel定时任务的实现
在 Laravel 中集成 Swoole 实现 WebSocket 服务器
阅读 2696基于 LaravelS 扩展包把 Swoole 集成到 Laravel 项目来实现 WebSocket 服务器,以便与客户端进行 WebSocket 通信从而实现广播功能。
微擎常用记录
阅读 928微擎常用记录
Laravel邮箱推送
阅读 2166Laravel发送邮件