1.Mysql 实现离线消息池。如果一个用户不在线,则其他用户发送给他的消息暂时存储在mysql。待该用户上线时,再从离线消息池取出发送。
2.Redis 实现每个连接websocket的服务都唯一绑定一个用户。通过用户账号 = fd 存到redis中。
微信小程序:
websocket.php代码:
<?php
//创建WebSocket Server对象,监听0.0.0.0:9501端口
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9501);
//连接Redis
$redis=new Redis();
$redis->connect('服务器地址',6379);
//连接MySQL
$con=mysqli_connect("服务器地址","数据库名称","数据库密码","数据表名称");
//监听WebSocket连接打开事件
$ws->on('Open', function ($ws, $request) {
});
//监听WebSocket消息事件
$ws->on('Message', function ($ws, $frame) use($redis) {
$data=json_decode($frame->data,true);
echo "{$frame->data}\n";
print_r($data['me']);
echo "\n";
switch($data['type']){
case 'open':
echo "我:".$data['me'];
echo "\n";
//将登录者“我”的fd存入至Redis
$redis->set($data['me'],$frame->fd);
$me=$redis->get($data['me']);
echo $me;
echo "\n";
//在数据库查询我离线时,别人给我发的消息
$sql = "SELECT `me`,`content` from chats where `to` = '{$data['me']}' order by `add_time` asc";
$result = mysqli_query($con,$sql);
//如果有,展示出来,即把消息推给客户端,即推送给“我”
if ($result) {
$re = [];
while($row = mysqli_fetch_assoc($result)) {
array_push($re, $row);
}
mysqli_free_result($result);
foreach ($re as $v) {
$msg = [
'msg' => $v['content']
];
$ws->push($frame->fd,json_encode($msg,true));
}
//推送给“我”之后,便将该消息删除处理
$sql = "DELETE FROM chats where `to` = '{$data['me']}'";
mysqli_query($con,$sql);
}
break;
case 'chat':
echo "给:".$data['to'];
echo "\n";
//从Redis中取出“当前好友”的fd
$to=$redis->get($data['to']);
echo "给的fd:".$to;
echo "\n";
//所有在线的用户
$fds = [];
foreach($ws->connections as $fd){
array_push($fds, $fd);
}
//判断“我”的“当前好友”是否在线
if (in_array($to,$fds)) {
$msg = [
'msg' => $data['msg'],
];
//如果在线,直接推送要发送的消息
$ws->push($to,json_encode($msg,256));
} else {
//如果不在线,将要发送的消息存入至数据表
$add_time = date('Y-m-d H:i:s');
$sql = "INSERT INTO chats(`to`,`me`,`content`,`add_time`) values ('{$data['to']}','{$data['me']}','{$data['msg']}','{$add_time}')";
mysqli_query($con,$sql);
}
break;
}
});
//监听WebSocket连接关闭事件
$ws->on('Close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$ws->start();
MySQL表字段:
运行效果:
用户11给用户a发消息,用户a不在线:
先把消息放置MySQL离线消息池:
用户a一上线,就看到用户11发来的消息:
并且数据表中的离线消息被删除:
都在线后就可以正常实时对话了:
另外,补充:简单实现两人3分钟未聊天服务端连接断开的功能:
首先,定义一个方法,用setTimeOut:
然后,在连接上服务端后和每次给服务端发送完一个消息后调用一下这个方法 :