用swoole+websocket和redis实现web客户端一对一聊天

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 = []; //所有在线的用户(打开聊天窗口的用户)
        foreach($server->connections as $fd){
            array_push($fds, $fd);
        }
        if(in_array($tofd,$fds)){
            $tmp['from'] = $data['from']; //消息来自于谁
            $tmp['content']  = $data['content']; //消息内容
            $re = json_encode($tmp);
            $server->push($tofd , $re);
        }else{
            //该玩家不在线(不在聊天室内),将信息发送到离线消息池
            $time = time();
            $sql = "INSERT INTO thinkphp5.app_offline (`to`,`from`,`content`,`status`,`addtime`) VALUES ('{
      $data['to']}','{
      $data['from']}','{
      $data['content']}','0','{
      $time}');";
            $GLOBALS['db']->query($sql);
        }
    }else if($data['flag'] == 'group'){
        //todo 群聊
        
    }else if($data['flag'] == 'all'){
        //全站广播
        foreach($server->connections as $fd){
            $server->push($fd , $data);
        }
    }  
});

$server->on('close', function ($ser, $fd) {
    echo "client {
      $fd} closed\n";
});

$server->start();
[/code]
[b]客户端代码:[/b]
[code]



    XST-app
    "Content-Type" content="text/html; charset=utf-8" />
    "X-UA-Compatible" content="IE=EmulateIE7" />
    "viewport" content="width=device-width, initial-scale=0.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
    "keywords" content="test" />
    "description" content="test" />
    "author" content="XST-APP" />
    "yes" name="apple-mobile-web-app-capable" />
    "black" name="apple-mobile-web-app-status-bar-style" />
    "telephone=no" name="format-detection" />
  



"header" class="head">
"wrap"> "menu_back">"javascript:history.go(-1);">
"title"> "title_d">

与 { $tonickname} 的聊天

"clear">
type="hidden" name="myemail" id="myemail" value="{ $myemail}" /> type="hidden" name="mynickname" id="mynickname" value="{ $mynickname}" /> type="hidden" name="myavatar" id="myavatar" value="{ $myavatar}" /> type="hidden" name="toemail" id="toemail" value="{ $toemail}" /> type="hidden" name="tonickname" id="tonickname" value="{ $tonickname}" /> type="hidden" name="toavatar" id="toavatar" value="{ $toavatar}" />
"speak_window">
"speak_box">
复制代码
"wenwen-footer">
"wenwen_btn left">"/static/images/jp_btn.png">
"wenwen_text left">
"write_box">type="text" class="left" onKeyUp="keyup()" maxlength="100" placeholder="请输入信息(100字以内)..." />
"wenwen_help right">
"opacity:0;" class="clear">
复制代码

数据表结构:

CREATE TABLE `app_offline` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `from` varchar(50) DEFAULT NULL COMMENT '离线发送方',
  `to` varchar(50) DEFAULT NULL COMMENT '离线接收方',
  `content` varchar(1000) DEFAULT NULL COMMENT '发送的离线内容',
  `status` tinyint(4) DEFAULT '0' COMMENT '发送状态:0-未发送,1-已发送',
  `addtime` int(11) DEFAULT NULL COMMENT '发送方发送时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
复制代码

具体效果:

到了这里很多朋友想深入学习swoole和laravel,swoft微服务在使用中遇到很多困难,我为大家准备了一套精品PHP中高级进阶学习教程,需要加微信:PHPopen888,还可加入大牛学习圈子,分享tp,laravel,swoole,swoft微服务、SQL性能优化,分布式、高并发等教程,各种大牛都是1-7年PHP开发者,每天还有11年的架构师做课程讲解,助你进阶中高级PHP程序员,增值涨薪!

到了这里很多朋友想深入学习swoole和laravel,swoft微服务在使用中遇到很多困难,我为大家准备了一套精品PHP中高级进阶学习教程,需要加微信:PHPopen888,还可加入大牛学习圈子,分享tp,laravel,swoole,swoft微服务、SQL性能优化,分布式、高并发等教程,各种大牛都是1-7年PHP开发者,每天还有11年的架构师做课程讲解,助你进阶中高级PHP程序员,增值涨薪!

转载于:https://juejin.im/post/5cc659fee51d456e853f81b9

你可能感兴趣的:(网络,数据库,php)