Redis 实现每个连接websocket的服务都唯一绑定一个用户。通过 用户账号 = websocket fd 存到redis中。
Mysql 实现离线消息池。如果一个用户不在线,则其他用户发送给他的消息暂时存储在mysql。待该用户上线时,再从离线消息池取出发送。
具体参考代码和相应注释:
$server = new swoole_websocket_server("0.0.0.0", 9052);
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$db = new mysqli('127.0.0.1', 'test', 'test', 'thinkphp5');
$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) {
$data = json_decode($frame->data,true);
if($data['flag'] == 'init'){
//用户刚连接的时候初始化,每个用户登录时记录该用户对应的fd
$GLOBALS['redis']->set($data['from'], $frame->fd);
//处理发给该用户的离线消息
$sql = "SELECT `from`,content FROM thinkphp5.app_offline WHERE `to`='{$data['from']}' AND `from`='{$data['to']}' AND `status`='0' ORDER BY addtime ASC;";
if ($result = $GLOBALS['db']->query($sql)) {
$re = array();
while ($row = $result->fetch_assoc()) {
array_push($re, $row);
}
$result->free();
foreach($re as $content){
$content = json_encode($content);
$server->push($frame->fd , $content);
}
//设置消息池中的消息为已发送
$sql = "UPDATE thinkphp5.app_offline SET `status`=1 WHERE `to`='{$data['from']}' AND `from`='{$data['to']}';";
$GLOBALS['db']->query($sql);
}
}else if($data['flag'] == 'msg'){
//非初始化的信息发送,一对一聊天,根据每个用户对应的fd发给特定用户
$tofd = $GLOBALS['redis']->get($data['to']); //消息要发给谁
$fds = []; //所有在线的用户(打开聊天窗口