基于swoole的网页一对一实时聊天
Posted Json159
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于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; width: 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:然后没有标记已读的消息,就是新消息提醒。
以上是关于基于swoole的网页一对一实时聊天的主要内容,如果未能解决你的问题,请参考以下文章
使用PHP+Swoole实现的网页即时聊天工具:PHPWebIM