聊天功能是很常见的一种功能,workerman是一款开源高性能异步php socket即时通讯框架。
什么是workerman?
workerman是一款开源高性能异步php socket即时通讯框架。支持高并发,超高稳定性,被广泛的用于手机app、移动通讯,微信小程序,手游服务端、网络游戏、php聊天室、硬件通讯、智能家居、车联网、物联网等领域的开发。支持tcp长连接,支持websocket、http等协议,支持自定义协议。拥有异步mysql、异步redis、异步http、mqtt物联网客户端、异步消息队列等众多高性能组件。
以下我们来搭建与配置一下workerman
第一步:先把workerman里需要用到的扩展compor下来。
第二步:到官方网站把demo全部下载下来,然后放到我们项目中的目录,我这里用的是laravel框架
图片中我就把整个项目都放在了http/controller/workerman中。
第三步:我们需要把把以下3个文件的引用部分修改为以下。不然会报路径错误
start_businessworker,start_gateway,start_register
修改完成后我们就可以在liunx直接运行对应的启动文件
如果你是在window下就双击start_for_win.bat运行
运行成功后,你就应该可以看到以下的界面
到此我们搭建基于workerman的通信环境就已经完成。接下来我们就可以根据自己的项目需求进行开发。在此向大家重点说明。我们所有的聊天是逻辑都在目录中的events.php进行修改。
下面给大家贴一下我编写的部分代码。如何实现一个聊天功能
event.php
<?php
/**
*thisfileispartofworkerman.
*
*licendunderthemitlicen
*forfullcopyrightandliceninformation,pleaethemit-licen.txt
*redistributionsoffilesmustretaintheabovecopyrightnotice.
*
*@authorwalkor<walkor@workerman.net>
*@copyrightwalkor<walkor@workerman.net>
*@linkhttp://www.workerman.net/
*@licenhttp://www.opensource.org/licens/mit-licen.phpmitlicen
*/
/**
*用于检测业务代码死循环或者长时间阻塞等问题
*如果发现业务卡死,可以将下面declare打开(去掉//注释),并执行phpstart.phpreload
*然后观察一段时间workerman.log看是否有process_timeout异常
*/
//declare(ticks=1);
/**
*聊天主逻辑
*主要是处理onmessageonclo
*/
u\gatewayworker\lib\gateway;
clasvents
{
/**
*当客户端连接上来的时候
*@param$client_id此id为gatewayworker自动生成id
*/
publicstaticfunctiononconnect($client_id)
{
gateway::ndtoclient($client_id,json_encode(array(
'type'=>'init',
'client_id'=>$client_id
)));
}
/**
*有消息时
*@paramint$client_id
*@parammixed$message
*/
publicstaticfunctiononmessage($client_id,$message)
{
//debug
echo"client:{$_rver['remote_addr']}:{$_rver['remote_port']}gateway:{$_rver['gateway_addr']}:{$_rver['gateway_port']}client_id:$client_idssion:".json_encode($_ssion)."onmessage:".$message."\n";
//客户端传递的是json数据
$message_data=json_decode($message,true);
if(!$message_data)
{
return;
}
//根据类型执行不同的业务
switch($message_data['type'])
{
//客户端回应服务端的心跳
ca'pong':
return;
//客户端登录message格式:{type:login,name:xx,room_id:1},添加到客户端,广播给所有客户端xx进入聊天室
ca'login':
//判断是否有房间号
if(!ist($message_data['room_id']))
{
thrownew\exception("\$message_data['room_id']nott.client_ip:{$_rver['remote_addr']}\$message:$message");
}
//把房间号昵称放到ssion中
$room_id=$message_data['room_id'];
$client_name=htmlspecialchars($message_data['client_name']);
$_ssion['room_id']=$room_id;
$_ssion['client_name']=$client_name;
//获取房间内所有用户列表
$clients_list=gateway::getclientssionsbygroup($room_id);
foreach($clients_listas$tmp_client_id=>$item)
{
$clients_list[$tmp_client_id]=$item['client_name'];
}
//$clients_list[$client_id]=$client_name;
//转播给当前房间的所有客户端,xx进入聊天室message{type:login,client_id:xx,name:xx}
$new_message=array('type'=>$message_data['type'],'client_id'=>$client_id,'client_name'=>htmlspecialchars($client_name),'time'=>date('y-m-dh:i:s'),'to'=>$message_data['to'],'room_id'=>$message_data['room_id'],
'from'=>$message_data['from'],'tag'=>$message_data['tag']);
gateway::ndtogroup($room_id,json_encode($new_message));
gateway::joingroup($client_id,$room_id);
//给当前用户发送用户列表
$new_message['client_list']=$clients_list;
gateway::ndtocurrentclient(json_encode($new_message));
return;
//客户端发言message:{type:say,to_client_id:xx,content:xx}
ca'say':
//非法请求
if(!ist($_ssion['room_id']))
{
thrownew\exception("\$_ssion['ro翟鸿燊简介om_id']nott.client_ip:{$_rver['remote_addr']}");
}
$room_id=$_ssion['room_id'];
$client_name=$_ssion['client_name'];
//私聊
//if($message_data['to_client_id']!='all')
//{
//$new_message=array(
//'type'=>'say',
//'from_client_id'=>$client_id,
//'from_client_name'=>$client_name,
//'to_client_id'=>$message_data['to_client_id'],
//'content'=>"<b>对你说:</b>".nl2br(htmlspecialchars($message_data['content'])),
//'time'=>date('y-m-dh:i:s'),
//);
//gateway::ndtoclient($message_data['to_client_id']黄山归来不看山,json_encode($new_message));
//$new_message['content']="<b>你对".htmlspecialchars($message_data['to_client_name'])."说:</b>".nl2br(htmlspecialchars($message_data['content']));
//returngateway::ndtocurrentclient(json_encode($new_message));
//}
$new_message=array(
'type'=>'say',
'from_client_id'=>$client_id,
'from_client_name'=>$client_name,
'to_client_id'=>'all',
'content'=>nl2br(htmlspecialchars($message_data['content'])),
'time'=>date('y-m-dh:i:s'),
);
returngateway::ndtogroup($room_id,json_encode($new_message));
}
}
/**
*当客户端断开连接时
*@paraminteger$client_id客户端id
*/
publicstaticfunctiononclo($client_id)
{
//debug
echo"client:{$_rver['remote_addr']}:{$_rver['remote_port']}gateway:{$_rver['gateway_addr']}:{$_rver['gateway_port']}client_id:$client_idonclo:''\n";
//从房间的客户端列表中删除
if(ist($_ssion['room_id']))
{
$room_id=$_ssion['room_id'];
$new_message=array('type'=>'logout','from_client_id'=>$client_id,'from_client_name'=>$_ssion['client_name'],'time'=>date('y-m-dh:i:s'));
gateway::ndtogroup($room_id,json_encode($new_message));
}
}
}
客户端页面
<!doctypehtml>
<htmllang="en">
<head>
<metachart="utf-8">
<title>与{{$to->name}}的对话</title>
<scripttype="text/javascript"src="{{ast('js')}}/swfobject.js"></script>
<scripttype="text/javascript"src="{{ast('js')}}/web_socket.js"></script>
<scripttype="text/javascript"src="{{ast('js')}}/jquery.min.js"></script>
<linkhref="{{ast('css')}}/jquery-sinaemotion-2.1.0.min.css"rel="externalnofollow"rel="stylesheet">
<linkhref="{{ast('css')}}/bootstrap.min.css"rel="externalnofollow"rel="stylesheet">
<linkhref="{{ast('css')}}/style.css"rel="externalnofollow"rel="stylesheet">
<scripttype="text/javascript"src="{{ast('js')}}/jquery-sinaemotion-2.1.0.min.js"></script>
{{--<scriptsrc="https://code.jquery.com/jquery-3.3.1.min.js"></script>--}}
</head>
<style>
#sinaemotion{
z-index:999;
width:373px;
padding:10px;
display:none;
font-size:12px;
background:#fff;
overflow:hidden;
position:absolute;
border:1pxsolid#e8e8e8;
top:100px;
left:542.5px;
}
</style>
<bodyonload="connect();"style="margin:auto;text-align:center;">
<divstyle="margin:auto;">
<divstyle="border:1pxsolidred;height:40px;width:500px;margin:auto;">
{{--对话窗口头部--}}
<div>
<divstyle="width:80px;height:40px;border:1pxsolidblue;float:left">
<imgsrc="{{$to->heading}}"width="80px"height="40px">
</div>
<divstyle="width:150px;height:40px;border:1pxsolidblue;float:left">
{{$to->name}}
<高二学习方法;/div>
</div>
{{--//对话窗口内容--}}
<divclass="content"style="width:500px;height:400px;border:1pxsolidgreen;margin-top:40px;overflow-y:auto">
{{--对方的头像与文字--}}
{{--<divstyle="min-height:50px;margin-top:10px;">--}}
{{--<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:left">--}}
{{--<imgsrc="{{$to->heading}}"width="50px"height="50px">--}}
{{--</div>--}}
{{--<divstyle="border:1pxsolidred;float:left;min-height:50px">dsadsadsadsadsa</div>--}}
{{--</div>--}}
{{--我的头像与文字--}}
{{--<divstyle="min-height:50px;margin-top:10px;">--}}
{{--<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:right">--}}
{{--<imgsrc="{{$from->heading}}"width="50px"height="50px">--}}
{{--</div>--}}
{{--<divstyle="border:1pxsolidred;float:right;min-height:50px">dsadsadsadsadsa</div>--}}
{{--</div>--}}
</div>
{{--对话发送窗口--}}
<formonsubmit="returnonsubmit();returnfal;"id="ajaxfrom">
<inputtype="hidden"name="to"value="{{$to->id}}">
<inputtype="hidden"name="from"value="{{$from->id}}">
<inputtype="hidden"name="room_id"value="{{$room}}">
<inputtype="hidden"name="tag"value="{{$tag}}">
<textareaid="textarea"name="content"class="input_text"style="margin:0px;width:501px;height:213px;"></如何去除颈纹textarea>
<divclass="say-btn">
<inputtype="button"class="btnbtn-defaultfacepull-left"value="表情"/>
<buttontype="submit"class="btnbtn-default">发表</button>
</div>
</form>
房间号{{$room}}
</div>
</div>
</body>
</html>
<scripttype="text/javascript">
if(typeofconsole=="undefined"){this.console={log:function(msg){}};}
//如果浏览器不支持websocket,会使用这个flash自动模拟websocket协议,此过程对开发者透明
web_socket_swf_location="/swf/websocketmain.swf";
//开启flash的websocketdebug
web_socket_debug=true;
varws,考研要过四级吗name,client_list={};
varto_client_id="";
//连接服务端初始化函数
functionconnect(){
//创建websocket届时可以替换为对应的服务器地址
ws=newwebsocket("ws://"+document.domain+":7272");
//当socket连接打开时,输入用户名
ws.onopen=onopen;
//当有消息时根据消息类型显示不同信息
ws.onmessage=onmessage;
//当连接丢失时,调用连接方法尝试重新连接
ws.onclo=function(){
console.log("连接关闭,定时重连");
connect();
};
//当操作报错时,返回异常错误
ws.onerror=function(){
console.log("出现错误");
};
//发送ajax获取当前房间的通话记录
$.post("/get_record",{"room":"{{$room}}"},
function(msg){
$.each(msg,function(v,k){
console.log(k);
//判断
if(k.tag!="{{$tag}}"){
$(".content").append(
'<divstyle="min-height:50px;margin-top:10px;">'+
'<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:left">'+
'<imgsrc="{{$to->heading}}"width="50px"height="50px">'+
'</div>'+
'<divstyle="border:1pxsolidred;float:left;min-height:50px">'+k.content+'</div>'+
'<div>'
).paremotion();
}el{
$(".content").append(
'<divstyle="min-height:50px;margin-top:10px;">'+
'<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:right">'+
'<imgsrc="{{$from->heading}}"width="50px"height="50px">'+
'</div>'+
'<divstyle="border:1pxsolidred;float:right;min-height:50px">'+k.content+'</div>'+
'<div>'
).paremotion();
}
})
});
}
//连接建立时发送登录信息
functiononopen()
{
varlogin_data='{"type":"login","client_name":"{{$from->name}}","room_id":"{{$room}}","to":"{{$to->id}}","from":"{{$from->id}}","tag":"{{$tag}}"}';
ws.nd(login_data);
console.log('登录成功')
}
//服务端发来消息时
functiononmessage(e)
{
vardata=json.par(e.data);
switch(data['type']){
//服务端ping客户端心跳
ca'ping':
ws.nd('{"type":"pong"}');
break;
//登录更新用户列表
ca'login':
//讲需要的发送id保存到本地to_client_id变量中
for(varpindata['client_list']){
to_client_id=p;
}
console.log(to_client_id);
break;
//发言
ca'say':
console.log(data);
say(data['from_client_id'],data['from_client_name'],data['content'],data['time']);
break;
//用户退出更新用户列表
ca'logout':
console.log(data);
break;
ca'init':
//此处可以发送ajax用于绑定不同的用户id和client
console.log(data);
break;
}
}
//提交对话
functiononsubmit(){
//先检查当前的对话是否超过20条记录数
varcount=true;
//发送ajax获取当前房间的通话记录
$.ajax({
url:"/check_count",
type:"post",
async:fal,
//cache:fal,
//contenttype:fal,
//processdata:fal,
data:{
'room':"1",
},
success:function(msg){
if(msg>10){
alert('当前的对话已经超过次数,请购买对应服务')
count=fal;
}
}
});
if(count){
varneirong=$("#textarea").val().replace(/"/g,'\\"').replace(/\n/g,'\\n').replace(/\r/g,'\\r');
//ajax先把对应的内容发送到后台录入,回调成功后才把信息发送
varfm=$("#ajaxfrom")[0];
varformdata=newformdata(fm);
$.ajax({
url:"/record",
type:"post",
cache:fal,
contenttype:fal,
processdata:fal,
data:formdata,
beforend:function(){
},
success:function(msg){
if(msg.code=="0"){
ws.nd('{"type":"say","to_client_id":"all","to_client_name":"{{$to->name}}","content":"'+neirong+'"}');
//清空文本框内容
$("#textarea").val("");
//强制定位光标
$("#textarea").focus();
}el{
}
}
});
}
returnfal;
}
//发言
functionsay(from_client_id,from_client_name,content,time){
//判断当前的用户名称与发送消息的名称是否一致
if("{{$from->name}}"==from_client_name){
$(".content").append(
'<divstyle="min-height:50px;margin-top:10px;">'+
'<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:right">'+
'<imgsrc="{{$from->heading}}"width="50px"height="50px">'+
'</div>'+
'<divstyle="border:1pxsolidred;float:right;min-height:50px">'+content+'</div>'+
'<div>'
).paremotion();
}el{
$(".content").append(
'<divstyle="min-height:50px;margin-top:10px;">'+
'<divstyle="width:50px;height:50px;border:1pxsolidred;margin-left:10px;float:left">'+
'<imgsrc="{{$to->heading}}"width="50px"height="50px">'+
'</div>'+
'<divstyle="border:1pxsolidred;float:left;min-height:50px">'+content+'</div>'+
'<div>'
).paremotion();
}
//$("#dialog").append('<divclass="speech_item"><imgsrc="http://lorempixel.com/38/38/?'+from_client_id+'"class="ur_icon"/>'+from_client_name+'<br>'+time+'<divstyle="clear:both;"></div><pclass="triangle-isoscelestop">'+content+'</p></div>').paremotion();
}
$(function(){
//全局用户id
lect_client_id='all';
//如果发送的用户有变化则对应的用户id进行替换
$("#client_list").change(function(){
lect_client_id=$("#client_listoption:lected").attr("value");
});
//表情选择
$('.face').click(function(event){
$(this).sinaemotion();
event.stoppropagation();
});
});
//document.write('<metaname="viewport"content="width=device-width,initial-scale=1">');
$("textarea").on("keydown",function(e){
//按enter键自动提交
if(e.keycode===13&&!e.ctrlkey){
e.preventdefault();
$('form').submit();
returnfal;
}
//按ctrl+enter组合键换行
if(e.keycode===13&&e.ctrlkey){
$(this).val(function(i,val){
returnval+"\n";
});
}
});
</script>
这两个代码片段其实就是主要运行的核心片段。其他框架的自带参数需要各位自己去根据文档去调试优化。到此基于workerman的聊天用于功能demo已经搭建完毕。
以上是文章全部内容,有需要学习交流的友人请加入swoole交流群的咱们一起,有问题一起交流,一起进步!前提是你是学技术的。感谢阅读!点此加入该群
本文发布于:2023-04-07 23:25:50,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/879db203b840760b5ecccdd73fe29bc3.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:试着用workerman开发一个在线聊天应用.doc
本文 PDF 下载地址:试着用workerman开发一个在线聊天应用.pdf
留言与评论(共有 0 条评论) |