需求分析

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

核心技术

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

数据表

  1. CREATE TABLE `msg` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `content` varchar(255) NOT NULL DEFAULT '' COMMENT '内容',
  4. `tid` int(11) NOT NULL DEFAULT '' COMMENT '接收用户id',
  5. `fid` int(11) NOT NULL DEFAULT '' COMMENT '发送用户id',
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COMMENT='消息表';
  1. CREATE TABLE `fd` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT,
  3. `uid` int(11) NOT NULL DEFAULT '' COMMENT '用户id',
  4. `fd` int(11) NOT NULL DEFAULT '' COMMENT '绑定id',
  5. PRIMARY KEY (`id`)
  6. ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT='用户绑定表';

Server端代码

  1. <?php
  2.  
  3. class Server
  4. {
  5. private $serv;
  6. private $conn = null;
  7. private static $fd = null;
  8.  
  9. public function __construct()
  10. {
  11. $this->initDb();
  12. $this->serv = new swoole_websocket_server("0.0.0.0", 9502);
  13. $this->serv->set(array(
  14. 'worker_num' => 8,
  15. 'daemonize' => false,
  16. 'max_request' => 10000,
  17. 'dispatch_mode' => 2,
  18. 'debug_mode' => 1
  19. ));
  20.  
  21. $this->serv->on('Open', array($this, 'onOpen'));
  22. $this->serv->on('Message', array($this, 'onMessage'));
  23. $this->serv->on('Close', array($this, 'onClose'));
  24.  
  25. $this->serv->start();
  26.  
  27. }
  28.  
  29. function onOpen($server, $req)
  30. {
  31. // $server->push($req->fd, json_encode(33));
  32. }
  33.  
  34. public function onMessage($server, $frame)
  35. {
  36. //$server->push($frame->fd, json_encode(["hello", "world"]));
  37. $pData = json_decode($frame->data);
  38. $data = array();
  39. if (isset($pData->content)) {
  40. $tfd = $this->getFd($pData->tid); //获取绑定的fd
  41. $data = $this->add($pData->fid, $pData->tid, $pData->content); //保存消息
  42. $server->push($tfd, json_encode($data)); //推送到接收者
  43. } else {
  44. $this->unBind(null,$pData->fid); //首次接入,清除绑定数据
  45. if ($this->bind($pData->fid, $frame->fd)) { //绑定fd
  46. $data = $this->loadHistory($pData->fid, $pData->tid); //加载历史记录
  47. } else {
  48. $data = array("content" => "无法绑定fd");
  49. }
  50. }
  51. $server->push($frame->fd, json_encode($data)); //推送到发送者
  52.  
  53. }
  54.  
  55. public function onClose($server, $fd)
  56. {
  57. $this->unBind($fd);
  58. echo "connection close: " . $fd;
  59. }
  60.  
  61. /*******************/
  62. function initDb()
  63. {
  64. $conn = mysqli_connect("192.168.1.122", "root", "a123456");
  65. if (!$conn) {
  66. die('Could not connect: ' . mysql_error());
  67. } else {
  68. mysqli_select_db($conn, "test");
  69. }
  70. $this->conn = $conn;
  71. }
  72.  
  73. public function add($fid, $tid, $content)
  74. {
  75. $sql = "insert into msg (fid,tid,content) values ($fid,$tid,'$content')";
  76. if ($this->conn->query($sql)) {
  77. $id = $this->conn->insert_id;
  78. $data = $this->loadHistory($fid, $tid, $id);
  79. return $data;
  80. }
  81. }
  82.  
  83. public function bind($uid, $fd)
  84. {
  85. $sql = "insert into fd (uid,fd) values ($uid,$fd)";
  86. if ($this->conn->query($sql)) {
  87. return true;
  88. }
  89. }
  90.  
  91. public function getFd($uid)
  92. {
  93. $sql = "select * from fd where uid=$uid limit 1";
  94. $row = "";
  95. if ($query = $this->conn->query($sql)) {
  96. $data = mysqli_fetch_assoc($query);
  97. $row = $data['fd'];
  98. }
  99. return $row;
  100. }
  101.  
  102. public function unBind($fd, $uid = null)
  103. {
  104. if ($uid) {
  105. $sql = "delete from fd where uid=$uid";
  106. } else {
  107. $sql = "delete from fd where fd=$fd";
  108. }
  109. if ($this->conn->query($sql)) {
  110. return true;
  111. }
  112. }
  113.  
  114. public function loadHistory($fid, $tid, $id = null)
  115. {
  116. $and = $id ? " and id=$id" : '';
  117. $sql = "select * from msg where ((fid=$fid and tid = $tid) or (tid=$fid and fid = $tid))" . $and;
  118. $data = [];
  119. if ($query = $this->conn->query($sql)) {
  120. while ($row = mysqli_fetch_assoc($query)) {
  121. $data[] = $row;
  122. }
  123. }
  124. return $data;
  125. }
  126. }
  127.  
  128. // 启动服务器
  129. $server = new Server();

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

启动服务器

  1. php Server.php

客户端代码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title></title>
  5. <meta charset="UTF-8">
  6. <script src="jquery-2.1.1.min.js"></script>
  7. <script src="jquery.json.js"></script> /*js地址:https://files.cnblogs.com/files/zenghansen/jquery.json-2.3.min.js*/
  1. <script type="text/javascript">
  2. var fid = 1; //发送者uid
  3. var tid = 2; //接收者uid
  4. var exampleSocket = new WebSocket("ws://192.168.1.17:9502");
  5. $(function () {
  6. exampleSocket.onopen = function (event) {
  7. console.log(event.data);
  8. initData(); //加载历史记录
  9. };
  10. exampleSocket.onmessage = function (event) {
  11. console.log(event.data);
  12. loadData($.parseJSON(event.data)); //导入消息记录,加载新的消息
  13. }
  14. })
  15. function sendMsg() {
  16. var pData = {
  17. content: document.getElementById('content').value,
  18. fid: fid,
  19. tid: tid,
  20. }
  21. if(pData.content == ''){
  22. alert("消息不能为空");
  23. return;
  24. }
  25. exampleSocket.send($.toJSON(pData)); //发送消息
  26. }
  27. function initData() {
  28. var pData = {
  29. fid: fid,
  30. tid: tid,
  31. }
  32. exampleSocket.send($.toJSON(pData)); //获取消息记录,绑定fd
  33. }
  34. function loadData(data) {
  35. for (var i = 0; i < data.length; i++) {
  36. var html = '<p>' + data[i].fid + '>' + data[i].tid + ':' + data[i].content + '</p>';
  37. $("#history").append(html);
  38. }
  39. }
  40. </script>
  41. </head>
  42. <body>
  43. <div id="history" style="border: 1px solid #ccc; width: 100px; height: auto">
  44. </div>
  45. <input type="text" id="content">
  46. <button onclick="sendMsg()">发送</button>
  47. </body>
  48. </html>

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

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

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

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

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

如有疑问请加作者qq:375161864

基于swoole的网页一对一实时聊天的更多相关文章

  1. Java进阶:基于TCP通信的网络实时聊天室

    目录 开门见山 一.数据结构Map 二.保证线程安全 三.群聊核心方法 四.聊天室具体设计 0.用户登录服务器 1.查看当前上线用户 2.群聊 3.私信 4.退出当前聊天状态 5.离线 6.查看帮助 ...

  2. 基于swoole+Redis的消息实时推送通知

    swoole+Redis将实时数据的推送 一 实现功能 设计师订单如果设计师未抢单,超时(5分钟)设计订单时时给设计师派送, 设计师公众号中收到派单信息 设计发布者收到派单成功信息 环境 centos ...

  3. 基于Android Classic Bluetooth的蓝牙聊天软件

    代码地址如下:http://www.demodashi.com/demo/12133.html BluetoothChat 基于Android Classic Bluetooth的蓝牙聊天软件,目前仅 ...

  4. 网页实时聊天之PHP实现websocket

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  5. 使用signalr实现网页和微信公众号实时聊天(上)

    最近项目中需要实现客户在公众号中和客服(客服使用后台网站系统)进行实时聊天的功能.折腾了一段时间,实现了这个功能.现在将过程记录下,以便有相同需求的同行可以参考,也是自己做个总结.这篇是上,用手机编辑 ...

  6. 网页实时聊天之PHP如何实现websocket

    网页实时聊天之PHP如何实现websocket 一.总结 一句话总结: 应用 PHP 的 socket 函数库:PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似 PHP 实现 ...

  7. SignalR实现网页实时聊天功能

    SignalR是利用html5 sokit方式实现网页的实时性,在客户端不支持html5的情况下通过轮询实现 实现原理是客户端发送的消息先去服务器,然后服务器根据需要将消息广播到需要接收信息的客户群. ...

  8. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  9. [转]网页实时聊天之js和jQuery实现ajax长轮询 PHP

    网页实时聊天之js和jQuery实现ajax长轮询 众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的 ...

随机推荐

  1. Flume内存溢出错误

    java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:) at java.lang.Ab ...

  2. Python基础3- 变量与数字

    1.Python变量不需要声明,其赋值操作既是变量声明和定义的过程;2.Python中每个变量在使用前都必须赋值,变量赋值后该变量才会被创建;3.Python变量是存储内存中的值,若变量赋值时内存中存 ...

  3. git 学习笔记3--status flow

    1.status 通过执行 git status 命令,查看输出的信息来理解文件所处的状态以及可能的动作. 1.1 nothing to commit (working directory clean ...

  4. The StringFormat property

    As we saw in the previous chapters, the way to manipulate the output of a binding before is shown is ...

  5. The 2015 China Collegiate Programming Contest D.Pick The Sticks hdu 5543

    Pick The Sticks Time Limit: 15000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others ...

  6. BZOJ3726 : PA2014Final Wykladzina

    从上到下枚举下底边,维护$a[i]$表示$i$向上延伸多少距离里面没有坏点,$b[i]$表示$i$向上延伸多少距离里面最多只有1个坏点. 设$l0[i],r0[i]$表示以$a[i]$为最小值,往左往 ...

  7. Android中有关relativeLayout 和EditText的一些属性

      http://www.cnblogs.com/jqyp/archive/2010/10/23/1859182.html RelativeLayout用到的一些重要的属性: 第一类:属性值为true ...

  8. hdu1019 Least Common Multiple

    Problem Description The least common multiple (LCM) of a set of positive integers is the smallest po ...

  9. OSG中的HUD

    OSG中的HUD 所谓HUD节点,说白了就是无论三维场景中的内容怎么改变,它都能在屏幕上固定位置显示的节点. 实现要点: 关闭光照,不受场景光照影响,所有内容以同一亮度显示 关闭深度测试 调整渲染顺序 ...

  10. 如何处理json字符转换为字典

    NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@?userName=%@&userPwd=%@& ...