利用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();