• 基于swoole的网页一对一实时聊天


    需求分析

    网站上实现一对一即时沟通,能查看聊天记录以及离线留言,新消息提醒。

    核心技术

    html5的websocket,php的swoole扩展http://wiki.swoole.com/

    数据表

    复制代码
    CREATE TABLE `msg` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `content` varchar(255) NOT NULL DEFAULT '' COMMENT '内容',
      `tid` int(11) NOT NULL DEFAULT '0' COMMENT '接收用户id',
      `fid` int(11) NOT NULL DEFAULT '0' COMMENT '发送用户id',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='消息表';
    复制代码
    CREATE TABLE `fd` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户id',
      `fd` int(11) NOT NULL DEFAULT '0' COMMENT '绑定id',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='用户绑定表';

    Server端代码

    复制代码
    <?php
    
    class Server
    {
        private $serv;
        private $conn = null;
        private static $fd = null;
    
        public function __construct()
        {
            $this->initDb();
            $this->serv = new swoole_websocket_server("0.0.0.0", 9502);
            $this->serv->set(array(
                'worker_num' => 8,
                'daemonize' => false,
                'max_request' => 10000,
                'dispatch_mode' => 2,
                'debug_mode' => 1
            ));
    
            $this->serv->on('Open', array($this, 'onOpen'));
            $this->serv->on('Message', array($this, 'onMessage'));
            $this->serv->on('Close', array($this, 'onClose'));
    
            $this->serv->start();
    
        }
    
        function onOpen($server, $req)
        {
            // $server->push($req->fd, json_encode(33));
        }
    
        public function onMessage($server, $frame)
        {
            //$server->push($frame->fd, json_encode(["hello", "world"]));
            $pData = json_decode($frame->data);
            $data = array();
            if (isset($pData->content)) {
                $tfd = $this->getFd($pData->tid); //获取绑定的fd
                $data = $this->add($pData->fid, $pData->tid, $pData->content); //保存消息
                $server->push($tfd, json_encode($data)); //推送到接收者
            } else {
                $this->unBind(null,$pData->fid); //首次接入,清除绑定数据
                if ($this->bind($pData->fid, $frame->fd)) {  //绑定fd
                    $data = $this->loadHistory($pData->fid, $pData->tid); //加载历史记录
                } else {
                    $data = array("content" => "无法绑定fd");
                }
            }
            $server->push($frame->fd, json_encode($data)); //推送到发送者
    
        }
    
    
        public function onClose($server, $fd)
        {
            $this->unBind($fd);
            echo "connection close: " . $fd;
        }
    
    
        /*******************/
        function initDb()
        {
            $conn = mysqli_connect("192.168.1.122", "root", "a123456");
            if (!$conn) {
                die('Could not connect: ' . mysql_error());
            } else {
                mysqli_select_db($conn, "test");
            }
            $this->conn = $conn;
        }
    
        public function add($fid, $tid, $content)
        {
            $sql = "insert into msg (fid,tid,content) values ($fid,$tid,'$content')";
            if ($this->conn->query($sql)) {
                $id = $this->conn->insert_id;
                $data = $this->loadHistory($fid, $tid, $id);
                return $data;
            }
        }
    
        public function bind($uid, $fd)
        {
            $sql = "insert into fd (uid,fd) values ($uid,$fd)";
            if ($this->conn->query($sql)) {
                return true;
            }
        }
    
        public function getFd($uid)
        {
            $sql = "select * from fd where uid=$uid limit 1";
            $row = "";
            if ($query = $this->conn->query($sql)) {
                $data = mysqli_fetch_assoc($query);
                $row = $data['fd'];
            }
            return $row;
        }
    
        public function unBind($fd, $uid = null)
        {
            if ($uid) {
                $sql = "delete from fd where uid=$uid";
            } else {
                $sql = "delete from fd where fd=$fd";
            }
            if ($this->conn->query($sql)) {
                return true;
            }
        }
    
        public function loadHistory($fid, $tid, $id = null)
        {
            $and = $id ? " and id=$id" : '';
            $sql = "select * from msg where ((fid=$fid and tid = $tid) or (tid=$fid and fid = $tid))" . $and;
            $data = [];
            if ($query = $this->conn->query($sql)) {
                while ($row = mysqli_fetch_assoc($query)) {
                    $data[] = $row;
                }
            }
            return $data;
        }
    }
    
    // 启动服务器
    $server = new Server();
    复制代码

    备注:swoole_websocket_server是基于tcp的长连接,仅支持cli模式运行。

    启动服务器

    php Server.php

    客户端代码

    复制代码
    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta charset="UTF-8">
        <script src="jquery-2.1.1.min.js"></script>
        <script src="jquery.json.js"></script>
        <script type="text/javascript">
            var fid = 1; //发送者uid
            var tid = 2; //接收者uid
            var exampleSocket = new WebSocket("ws://192.168.1.17:9502");
            $(function () {
                exampleSocket.onopen = function (event) {
                    console.log(event.data);
                    initData(); //加载历史记录
                };
                exampleSocket.onmessage = function (event) {
                    console.log(event.data);
                    loadData($.parseJSON(event.data)); //导入消息记录,加载新的消息
                }
    
    
            })
            function sendMsg() {
                var pData = {
                    content: document.getElementById('content').value,
                    fid: fid,
                    tid: tid,
                }
                if(pData.content == ''){
                    alert("消息不能为空");
                    return;
                }
                exampleSocket.send($.toJSON(pData)); //发送消息
            }
            function initData() {
                var pData = {
                    fid: fid,
                    tid: tid,
                }
                exampleSocket.send($.toJSON(pData)); //获取消息记录,绑定fd
            }
            function loadData(data) {
                for (var i = 0; i < data.length; i++) {
                    var html = '<p>' + data[i].fid + '>' + data[i].tid + ':' + data[i].content + '</p>';
                    $("#history").append(html);
                }
            }
        </script>
    </head>
    <body>
    <div id="history" style="border: 1px solid #ccc;  100px; height: auto">
    
    </div>
    <input type="text" id="content">
    <button onclick="sendMsg()">发送</button>
    </body>
    </html>
    复制代码

    ps1:再复制一份客户端,修改一下发送者你接收者的uid,即可进行模拟实时聊天。

    ps2:此代码已经实现了加载历史记录的功能

    ps3:若要增加新消息提醒功能,msg还需增加一个已读标示,然后推送给接收者的时候 

    if($server->push($tfd, json_encode($data))){
          //标记已读  
    }    

    ps4:然后没有标记已读的消息,就是新消息提醒。

    原网址:https://www.cnblogs.com/zenghansen/p/5084738.html

    世事洞明皆学问
  • 相关阅读:
    离场飞越转弯全家福
    画一个PBN大角度飞越转弯保护区
    画一个小角度飞越转弯保护区
    Point Estimation
    Random variable
    心流
    Survey sampling
    Distribution
    数学分析总结
    topological space
  • 原文地址:https://www.cnblogs.com/Json159/p/11291657.html
Copyright © 2020-2023  润新知