ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解


Posted in PHP onApril 02, 2019

本文实例讲述了ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例。分享给大家供大家参考,具体如下:

ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展(相关文章:Linux下源码包安装使用Swoole扩展)

在tp5的项目根目录下执行composer命令安装think-swoole:

composer require topthink/think-swoole

ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解

安装成功:

ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解

话不多说,直接上代码:

新建WebSocket.php控制器:

(监听端口要确认服务器放行,宝塔环境还需要添加安全组规则)

<?php

namespace app\home\controller;
use think\swoole\Server;
class WebSocket extends Server
{
  protected $host = '0.0.0.0'; //监听所有地址
  protected $port = 9501; //监听9501端口
  protected $serverType = 'socket';
  protected $option = [ 
    'worker_num'=> 4, //设置启动的Worker进程数
    'daemonize'	=> false, //守护进程化(上线改为true)
    'backlog'	=> 128, //Listen队列长度
    'dispatch_mode' => 2, //固定模式,保证同一个连接发来的数据只会被同一个worker处理

    //心跳检测:每60秒遍历所有连接,强制关闭10分钟内没有向服务器发送任何数据的连接
    'heartbeat_check_interval' => 60,
    'heartbeat_idle_time' => 600
  ];

  //建立连接时回调函数
  public function onOpen($server,$req)
  {
    $fd = $req->fd;//客户端标识
    $uid = $req->get['uid'];//客户端传递的用户id
    $token = $req->get['token'];//客户端传递的用户登录token
    
    //省略token验证逻辑......
    if (!$token) {
      $arr = array('status'=>2,'message'=>'token已过期');
      $server->push($fd, json_encode($arr));
      $server->close($fd);
      return;
    }
    //省略给用户绑定fd逻辑......
    echo "用户{$uid}建立了连接,标识为{$fd}\n";
  }

  //接收数据时回调函数
  public function onMessage($server,$frame)
  {
    $fd = $frame->fd;
    $message = $frame->data;

    //省略通过fd查询用户uid逻辑......
    $uid = 666;
    $data['uid'] = $uid;
    $data['message'] = '用户'.$uid.'发送了:'.$message;
    $data['post_time'] = date("m/d H:i",time());
    $arr = array('status'=>1,'message'=>'success','data'=>$data);

    //仅推送给当前连接用户
    //$server->push($fd, json_encode($arr));
    
    //推送给全部连接用户
    foreach($server->connections as $fd) {
      $server->push($fd, json_encode($arr));
    } 
  }

  //连接关闭时回调函数
  public function onClose($server,$fd)
  {
    echo "标识{$fd}关闭了连接\n";
  }
}

前端演示页面:

(省略控制器判断登录状态、分配数据逻辑......)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>Chat</title>
<link rel="stylesheet" type="text/css" href="/static/liaotian/chat.css" rel="external nofollow" />
<script src="/static/liaotian/js/jquery.min.js"></script>
<script src="/static/liaotian/js/flexible.js"></script>
</head>
<body>
  <header class="header">
    <a class="back" href="javascript:history.back()" rel="external nofollow" ></a>
    <h5 class="tit">在线聊天</h5>
    <a href=""><div class=" rel="external nofollow" right">退出</div></a>
  </header>

  <!-- 聊天内容 start-->
	<div class="message"> </div>
  <!-- 聊天内容 end-->

  <!-- 底部 start-->
  <div class="footer">
    <img id="setbtn" src="/static/liaotian/images/hua.png" alt="" />
    <img src="/static/liaotian/images/xiaolian.png" alt="" />
    <input type="text" id="msg" value="" maxlength="300">
    <p style="background: rgb(17, 79, 142);" id="sendBtn">发送</p>
  </div>
  <!-- 底部 end-->
</body>
</html>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/layer/3.1.0/layer.js"></script>
<script type="text/javascript">
$(function () {
  var uid = 666;//当前用户id
  var token = 'abcdefg';//用户token

  //判断浏览器是否支持WebSocket
  var supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window;
  if (supportsWebSockets) {
    //建立WebSocket连接(ip地址换成自己主机ip)
    var ws = new WebSocket("ws://127.0.0.1:9501?uid="+uid+"&token="+token);
    ws.onopen = function () {
      layer.msg('服务器连接成功',{shade:0.1,icon:1,time:600});
    };
    ws.onerror = function () {
      layer.msg('服务器连接失败',{shade:0.1,icon:2,time:600});
    };
    ws.onmessage = function (evt) {
      var data = $.parseJSON(evt.data);
      //错误提示
      if(data.status != 1){
        layer.alert(data.message,{icon:2});
        return;
      }
      //消息返回
      if (data.status==1 && data.data.message!='') {
        var html = "";
        if (data.data.uid == uid) {
          html += "<div style='word-break:break-all' class=\"show\"><div class=\"time\">"+data.data.post_time+"</div><div class=\"msg\"><img src=\""+data.data.head_img+"\" alt=\"\" /><p><i clas=\"msg_input\"></i>"+data.data.message+"</p></div></div>";
        }else{
          html += "<div style='word-break:break-all' class=\"send\"><div class=\"time\">"+data.data.post_time+"</div><div class=\"msg\"><img src=\""+data.data.head_img+"\" alt=\"\" /><p><i clas=\"msg_input\"></i>"+data.data.message+"</p></div></div>";
        }
      }
      $(".message").append(html);
      setTimeout(function () {
        ($('.message').children("div:last-child")[0]).scrollIntoView();//向上滚动
      },100);
    };
    ws.onclose = function (res) {
      
    };
    //按钮发送
    $("#sendBtn").click(function () {
      var contents = $("#msg").val().trim();
      if(contents == null || contents == ""){
        layer.msg('内容为空',{shade:0.1,icon:2,time:600});      
        return false;
      }else{
      	ws.send(contents);
      	$("#msg").val("");
      }
    });
    //回车发送
    $("#msg").keydown(function (evel) {
      var that = $(this);
      if (evel.keyCode == 13) {
        evel.cancelBubble = true;
        evel.preventDefault();
        evel.stopPropagation();
        var contents = that.val().trim();
        if(contents == null || contents == ""){
          layer.msg('内容为空',{shade:0.1,icon:2,time:600});       
          return false;
        }else{
          ws.send(contents);
          that.val("");
        }
      }
    });
  }else{
    layer.alert("您的浏览器不支持 WebSocket!");
  }
});
</script>

服务器移到项目根目录开启服务:

php public/index.php Websocket/start

(这里的路径,是因为我绑定了home模块为默认模块,tp5默认情况是:php public/index.php index/Websocket/start

开启成功,查看端口已经被监听:

lsof -i:9501

ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解

 演示效果如下:

ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解

服务器监听如下:

ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解

用户每刷新重连一次,fd标识都会改变。

希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助。

PHP 相关文章推荐
Zend引擎的发展 [15]
Oct 09 PHP
E路文章系统PHP
Dec 11 PHP
php仿discuz分页效果代码
Oct 02 PHP
php缓冲 output_buffering的使用详解
Jun 13 PHP
Yii实现MySQL多数据库和读写分离实例分析
Dec 03 PHP
php简单生成随机数的方法
Jul 30 PHP
PHP实现HTML页面静态化的方法
Nov 04 PHP
php关闭warning问题的解决方法
May 17 PHP
golang与php实现计算两个经纬度之间距离的方法
Jul 22 PHP
Laravle eloquent 多对多模型关联实例详解
Nov 22 PHP
使用SMB共享来绕过php远程文件包含的限制执行RFI的利用
May 31 PHP
php和html的区别点详细总结
Sep 24 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
Apr 02 #PHP
Laravel 中创建 Zip 压缩文件并提供下载的实现方法
Apr 02 #PHP
phpStorm+XDebug+chrome 配置详解
Apr 01 #PHP
PHP+Oracle本地开发环境搭建方法详解
Apr 01 #PHP
phpstorm 配置xdebug的示例代码
Mar 31 #PHP
PHP文件后缀不强制为.php方法
Mar 31 #PHP
PHP中md5()函数的用法讲解
Mar 30 #PHP
You might like
简单的php 验证图片生成函数
2009/05/21 PHP
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
PHP校验ISBN码的函数代码
2011/01/17 PHP
PHP实现计算器小功能
2020/08/28 PHP
js中更短的 Array 类型转换
2011/10/30 Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
2012/01/15 Javascript
js数组去重的常用方法总结
2014/01/24 Javascript
js实现在网页上简单显示时间的方法
2015/03/02 Javascript
直接拿来用的15个jQuery代码片段
2015/09/23 Javascript
canvas 绘制圆形时钟
2017/02/22 Javascript
使用nodejs爬取前程无忧前端技能排行
2017/05/06 NodeJs
基于vue2实现上拉加载功能
2017/11/28 Javascript
vue编译打包本地查看index文件的方法
2018/02/23 Javascript
Vue Cli 3项目使用融云IM实现聊天功能的方法
2019/04/19 Javascript
iview的table组件自带的过滤器实现
2019/07/12 Javascript
Python模块学习 datetime介绍
2012/08/27 Python
python显示生日是星期几的方法
2015/05/27 Python
Python列表推导式与生成器用法分析
2018/08/02 Python
Python基于plotly模块实现的画图操作示例
2019/01/23 Python
python获取点击的坐标画图形的方法
2019/07/09 Python
python图的深度优先和广度优先算法实例分析
2019/10/26 Python
Python 切分数组实例解析
2019/11/07 Python
Python实现CNN的多通道输入实例
2020/01/17 Python
pycharm中使用request和Pytest进行接口测试的方法
2020/07/31 Python
详解如何修改jupyter notebook的默认目录和默认浏览器
2021/01/24 Python
英国知名的皮手套品牌:Dents
2016/11/13 全球购物
求职信模板怎么做
2014/01/26 职场文书
放飞中国梦演讲稿
2014/04/23 职场文书
专科应届毕业生求职信
2014/06/04 职场文书
小学雷锋月活动总结
2014/07/03 职场文书
母亲节寄语大全
2015/02/27 职场文书
我是特种兵观后感
2015/06/11 职场文书
zabbix agent2 监控oracle数据库的方法
2021/05/13 Oracle
CSS极坐标的实例代码
2021/06/03 HTML / CSS
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电
springcloud整合seata
2022/05/20 Java/Android