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 相关文章推荐
adodb与adodb_lite之比较
Dec 31 PHP
开启CURL扩展,让服务器支持PHP curl函数(远程采集)
Mar 19 PHP
fleaphp crud操作之find函数的使用方法
Apr 23 PHP
PHP If Else(elsefi) 语句
Apr 07 PHP
php统计时间和内存使用情况示例分享
Mar 13 PHP
修改ThinkPHP缓存为Memcache的方法
Jun 25 PHP
从零开始学YII2框架(五)快速生成代码工具 Gii 的使用
Aug 20 PHP
php实现根据字符串生成对应数组的方法
Sep 22 PHP
php使用ereg验证文件上传的方法
Dec 16 PHP
HTML中嵌入PHP的简单方法
Feb 16 PHP
PHP与SQL语句常用大全
Dec 10 PHP
THINKPHP-Apache服务器中使用Alias虚拟目录URL重写 隐藏index.php
Mar 09 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
mysql中存储过程、函数的一些问题
2007/02/14 PHP
javascript 小型动画组件与实现代码
2010/06/02 PHP
PHP中include与require使用方法区别详解
2013/10/19 PHP
laravel自定义分页效果
2017/07/23 PHP
php魔法函数与魔法常量使用介绍
2017/07/23 PHP
document.designMode的功能与使用方法介绍
2007/11/22 Javascript
javascript验证只能输入数字和一个小数点示例
2013/10/21 Javascript
整理AngularJS中的一些常用指令
2015/06/16 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
Backbone View 之间通信的三种方式
2016/08/09 Javascript
简单理解Vue条件渲染
2016/12/03 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
2016/12/08 Javascript
JS正则匹配中文的方法示例
2017/01/06 Javascript
JavaScript轮播图简单制作方法
2017/02/20 Javascript
webstorm中配置nodejs环境及npm的实例
2018/05/15 NodeJs
纯JS实现出生日期[年月日]下拉菜单效果
2018/06/01 Javascript
[36:52]DOTA2真视界:基辅特锦赛总决赛
2017/05/21 DOTA
python分析apache访问日志脚本分享
2015/02/26 Python
Python运用于数据分析的简单教程
2015/03/27 Python
修改Python的pyxmpp2中的主循环使其提高性能
2015/04/24 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
python中的数据结构比较
2019/05/13 Python
Python 多个图同时在不同窗口显示的实现方法
2019/07/07 Python
用openCV和Python 实现图片对比,并标识出不同点的方式
2019/12/19 Python
为什么黑客都用python(123个黑客必备的Python工具)
2020/01/31 Python
python随机生成大小写字母数字混合密码(仅20行代码)
2020/02/01 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
大数据分析用java还是Python
2020/07/06 Python
Python如何读写二进制数组数据
2020/08/01 Python
django 获取字段最大值,最新的记录操作
2020/08/09 Python
施华洛世奇澳大利亚官网:SWAROVSKI澳大利亚
2017/01/06 全球购物
JBL英国官网:JBL UK
2018/07/04 全球购物
计算机专业毕业生求职信分享
2013/12/24 职场文书
个人求职信范文分享
2014/01/31 职场文书
道路交通事故赔偿协议书
2014/10/24 职场文书
女儿满月酒致辞
2015/07/29 职场文书