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 相关文章推荐
一篇入门的php Class 文章
Apr 04 PHP
Phpbean路由转发的php代码
Jan 10 PHP
php 操作数组(合并,拆分,追加,查找,删除等)
Jul 20 PHP
深入apache配置文件httpd.conf的部分参数说明
Jun 28 PHP
使用PHP下载CSS文件中的图片的代码
Sep 24 PHP
php求正负数数组中连续元素最大值示例
Apr 11 PHP
PHP中array_slice函数用法实例详解
Nov 25 PHP
PHP安装GeoIP扩展根据IP获取地理位置及计算距离的方法
Jul 01 PHP
php实现xml与json之间的相互转换功能实例
Jul 07 PHP
PHP实现的DES加密解密封装类完整实例
Apr 29 PHP
Laravel框架分页实现方法分析
Jun 12 PHP
laravel 实现登陆后返回登陆前的页面方法
Oct 03 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&amp;java(二)
2006/10/09 PHP
删除无限分类并同时删除它下面的所有子分类的方法
2010/08/08 PHP
探讨:array2xml和xml2array以及xml与array的互相转化
2013/06/24 PHP
php+mysqli预处理技术实现添加、修改及删除多条数据的方法
2015/01/30 PHP
Yii+MYSQL锁表防止并发情况下重复数据的方法
2016/07/14 PHP
yii2多图上传组件的使用教程
2018/05/10 PHP
laravel 实现设置时区的简单方法
2019/10/10 PHP
Yii框架where查询用法实例分析
2019/10/22 PHP
静态页面的值传递(三部曲)
2006/09/25 Javascript
IE 缓存策略的BUG的解决方法
2007/07/21 Javascript
jQuery选择器简明总结(含用法实例,一目了然)
2014/04/25 Javascript
JavaScript中伪协议 javascript:使用探讨
2014/07/18 Javascript
JQuery中clone方法复制节点
2015/05/18 Javascript
jquery常用的12个小功能
2016/07/22 Javascript
jQuery子元素过滤选择器用法示例
2016/09/09 Javascript
前端面试知识点锦集(JavaScript篇)
2016/12/28 Javascript
利用jqgrid实现上移下移单元格功能
2018/11/07 Javascript
JS实现继承的几种常用方式示例
2019/06/22 Javascript
layui清空,重置表单数据的实例
2019/09/12 Javascript
javascript实现计算器功能
2020/03/30 Javascript
vue基础知识--axios合并请求和slot
2020/06/04 Javascript
JavaScript实现切换多张图片
2021/01/27 Javascript
Python的Django框架中的表单处理示例
2015/07/17 Python
详解Python中的变量及其命名和打印
2016/03/11 Python
Python获取本机所有网卡ip,掩码和广播地址实例代码
2018/01/22 Python
使用CodeMirror实现Python3在线编辑器的示例代码
2019/01/14 Python
Python 使用list和tuple+条件判断详解
2019/07/30 Python
详解Django配置优化方法
2019/11/18 Python
python使用ctypes库调用DLL动态链接库
2020/10/22 Python
纯CSS3实现手风琴风格菜单具体步骤
2013/05/06 HTML / CSS
详解HTML5 Canvas绘制不规则图形时的非零环绕原则
2016/03/21 HTML / CSS
小学毕业典礼演讲稿
2014/09/09 职场文书
怎样写辞职信
2015/02/27 职场文书
幼儿园六一主持词
2015/06/30 职场文书
《狼牙山五壮士》读后感:宁死不屈,视死如归
2019/08/16 职场文书
SQL Server使用T-SQL语句批处理
2022/05/20 SQL Server