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 相关文章推荐
substr()函数中文版
Oct 09 PHP
PHP_Cooikes不同页面无法传递的解决方法
Mar 07 PHP
ThinkPHP Mobile使用方法简明教程
Jun 18 PHP
PHP伪静态Rewrite设置之APACHE篇
Jul 30 PHP
php开发中的页面跳转方法总结
Apr 26 PHP
简单谈谈php中的unicode和utf8编码
Jun 10 PHP
PHP curl模拟登录带验证码的网站
Nov 30 PHP
PHP经典算法集锦【经典收藏】
Sep 14 PHP
Yii核心验证器api详解
Nov 23 PHP
PHP使用栈解决约瑟夫环问题算法示例
Aug 27 PHP
PHP递归的三种常用方式
Feb 28 PHP
实例说明js脚本语言和php脚本语言的区别
Apr 04 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操作Memcache实例介绍
2013/06/14 PHP
PHP输出当前进程所有变量/常量/模块/函数/类的示例
2013/11/07 PHP
Yii框架获取当前controlle和action对应id的方法
2014/12/03 PHP
PHP调用MySQL存储过程并返回值的方法
2014/12/26 PHP
PHP Post获取不到非表单数据的问题解决办法
2018/02/27 PHP
JavaScript的document对象和window对象详解
2010/12/30 Javascript
jquery调用wcf并展示出数据的方法
2011/07/07 Javascript
flash调用js中的方法,让js传递变量给flash的办法及思路
2013/08/07 Javascript
5分钟理解JavaScript中this用法分享
2013/11/09 Javascript
Nodejs实现的一个简单udp广播服务器、客户端
2014/09/25 NodeJs
45个JavaScript编程注意事项、技巧大全
2015/02/11 Javascript
AngularJS使用ngMessages进行表单验证
2015/12/27 Javascript
不能不知道的10个angularjs英文学习网站
2016/03/23 Javascript
js与applet相互调用的方法
2016/06/22 Javascript
微信小程序 开发指南详解
2016/09/27 Javascript
vue数字类型过滤器的示例代码
2017/09/07 Javascript
微信小程序swiper组件用法实例分析【附源码下载】
2017/12/07 Javascript
jQuery实现的简单获取索引功能示例
2018/06/04 jQuery
解决angularJS中input标签的ng-change事件无效问题
2018/09/13 Javascript
nodejs的安装使用与npm的介绍
2019/09/11 NodeJs
Auto.JS实现抖音刷宝等刷视频app,自动点赞,自动滑屏,自动切换视频功能
2020/05/08 Javascript
vue实现简单计算商品价格
2020/09/14 Javascript
Python API 自动化实战详解(纯代码)
2019/06/11 Python
python 返回一个列表中第二大的数方法
2019/07/09 Python
Flask框架请求钩子与request请求对象用法实例分析
2019/11/07 Python
世界最大域名注册商:GoDaddy
2016/07/24 全球购物
雅高酒店中国:Accorhotels.com China
2018/03/26 全球购物
Famous Footwear加拿大:美国多品牌运动休闲鞋店
2018/12/05 全球购物
给孩子的新年寄语
2014/04/08 职场文书
公务员中国梦演讲稿
2014/08/19 职场文书
工商管理专业毕业生自我鉴定2014
2014/10/04 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
利用python做表格数据处理
2021/04/13 Python
MySQL数据库压缩版本安装与配置详细教程
2021/05/21 MySQL
面试分析分布式架构Redis热点key大Value解决方案
2022/03/13 Redis
Python线程池与GIL全局锁实现抽奖小案例
2022/04/13 Python