首页 > 数据库 > ThinkPHP5结合Swoole开发实现WebSocket在线聊天
2019
09-07

ThinkPHP5结合Swoole开发实现WebSocket在线聊天

ThinkPHP使用Swoole需要安装 think-swoole Composer包,前提系统已经安装好了Swoole PECL 拓展


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


安装成功:

代码如下新建WebSocket.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";
??}
} 


前端演示页面:省略控制器判断登录状态、分配数据逻辑......
 <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>Chattitle> <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> ?? ????<div?class="message">?div> ?? ?? ??<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> ?? 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?+=?""+data.data.post_time+"
<>+data.data.head_img+"\"?alt=\"\"?/>

"

+data.data.message+"