利用swoole实现websocket聊天demo
我这里只有后端代码前端的html没有,调试可以利用在线websocket来调试
*想要看前后端效果可以去https://github.com/Johnson19900110/ChatRoom(改一下ip和端口就可以用了 亲测没毛病,感谢大佬的)
代码主要是参考上面这位大佬的,在此基础加了
1、心跳检测、
2、异常账号登陆判定、
3、redis、
4、点对点发送消息。
先把上面github这个大佬的看懂了 新加的几个功能代码就能看懂了
*一定要先把上面的看懂 再来看下面的代码 不然会懵逼
*php server.php直接在命令行运行就好了
新增
1、心跳检测:新增两个参数具体看文档
heartbeat_check_interval heartbeat_idle_time
2、异常连接判定:就是在连接的时候让前端传一个token之类的过来 判断是否是异常连接,如果是直接断掉
// if (!isset($request->get) || !isset($request->get['uid'])) { // $this->server->close($request->fd); // return false; // }
3、redis(和原生一样redis)
4、点对点发送消息:就是指定fd来push就好了
5、多房间聊天:可以利用redis之类存储对fd进行分组,就可以实现多房间聊天了
6、发送文件:可以客户端先把文件上传第三方平台(七牛云),然后发送文件链接
server.php代码
<?php class chat{ const HOST = '0.0.0.0';//ip地址 0.0.0.0代表接受所有ip的访问 const PART = 9095;//端口号 private $server = null;//单例存放websocket_server对象 private $users = array(); //保存连接的用户,fd=>nickname的形式保存 public function start(){ $this->server = new swoole_websocket_server(self::HOST,self::PART); $this->server->set([ 'daemonize' => 0, 'worker_num' => 4, 'task_worker_num' => 10, 'max_request' => 1000, 'heartbeat_check_interval' => 60, //心跳检测 60秒检测一次 100秒 对方向服务器发消息 自动断开 会回调onClose 'heartbeat_idle_time' => 1000, //心跳检测 60秒检测一次 100秒 对方向服务器发消息 自动断开 不会回调用onClose ]); $this->server->on("open",[$this,'onOpen']); $this->server->on("message",[$this,'onMessage']); $this->server->on("task",[$this,'onTask']); $this->server->on("finish",[$this,'onFinish']); $this->server->on("close",[$this,'onClose']); $this->server->start(); } public function onOpen($server, $request){ //判断是不是非法连接 也可以传递token来判断有没有登陆 此处必须带uid不然就会关闭连接 比如:ws://127.0.0.1:9095?uid=1 // if (!isset($request->get) || !isset($request->get['uid'])) { // $this->server->close($request->fd); // return false; // } //连接redis (这里用的原生redis) $redis = $this->redisConnect(); //存一些必要的数据进redis(这里只是测试redis 后面并没有用到) $redis->set($request->get['uid'],json_encode(["fd"=>$request->fd])); //给登陆的用户端发送一个连接成功的信息 $server->push($request->fd, json_encode(['code' => 200, 'message' => "online suce $request->fd","type"=>1])); //1系统消息,2用户聊天 } public function onMessage($server, $frame){ $data = json_decode($frame->data); switch ($data->type) { case 'init': case 'INIT': $this->users[$frame->fd] = $data->message; $message = '欢迎' . $data->message . '加入了聊天室'; $response = array( 'type' => 1, // 1代表系统消息,2代表用户群聊天 'message' => $message ); break; case 'chat': case 'CHAT': $message = $data->message; $response = array( 'type' => 2, // 1代表系统消息,2代表用户群聊天 'username' => $this->users[$frame->fd], 'message' => $message ); break; case 'to': //这里是点对点发送 ,这里的测试用websocket在线测试,思路就是指定fd就好了 case 'TO': $message = $data->message; $response = array( 'type' => 3, // 1代表系统消息,2代表用户群聊天 3代表点对点 'username' => $this->users[$frame->fd], 'message' => $message, 'to' => $data->fd, ); break; default: return false; } $this->server->task($response); } public function onTask($server, $task_id, $from_id, $message) { if ($message["type"] == 3){ //这里是点对点发送 ,这里的测试用websocket在线测试,思路就是指定fd就好了 $this->server->push($message["to"], json_encode($message)); } else{ foreach ($this->server->connections as $fd){ $this->server->push($fd, json_encode($message)); } } } public function onFinish($server, $task_id, $data) { } public function onClose($server, $fd) { $username = $this->users[$fd]; unset($this->users[$fd]); if( $username ) { $response = array( 'type' => 1, // 1代表系统消息,2代表用户聊天 'message' => $username . '离开了聊天室' ); $this->server->task($response); } } public function redisConnect() { $redis = new Redis(); $redis->connect("192.168.1.222", "6379"); $redis->auth("axt1314"); $redis->select(2); return $redis; } } $ws = new chat(); $ws->start();