经由搜索,找到了一个jQuery.danmu.js的开源项目。看了一下star的人还挺多github.com/chiruom/jquery.danmu.js
进入demo目录,先运行一下例子看当作果呗。
果真,点开往后涌现了一个高大上的页面,略看一下功能还挺多。但是问题来了,为啥我点击开始,一点反应也木有呢。

原来是源文件中的jQuery插件的问题。在src目录下,并没有该文件
<scriptsrc=\公众../src/jquery-2.1.4.min.js\"大众></script>
算了还是调用百度的在线jQuery插件吧
<scriptsrc=\"大众http://libs.baidu.com/jquery/2.1.4/jquery.min.js\"大众></script>
再一刷新,不出预见,成功运行。
后端,那就先来说说弹幕的事理吧。弹幕,就相称于一个公共谈天室,都是一个客户端发送给做事端,做事端再将收到的广播给其他的客户端。
用传统的ajax轮询吗?弗成,这样效率太低,想想各大火爆的直播平台都是同一韶光几万人在线,几千人同时发弹幕,如果靠ajax轮询一个PHP接口的话做事器会吃不消的。且弹幕存储方案略显繁芜,有人问为什么要存储呢?由于ajax利用的HTTP协议是无状态协议,A客户端和B客户端之间对付做事器来说没有任何标志,如果做事器要确保A客户端和B客户端分别在两次要求的时候做事器只返回这两个客户端没有获取过的弹幕,那么做事器端就必须利用一个缓存来标识某某客户端看过哪条弹幕。综上所述ajax可以实现小规模的弹幕通信方案,但是很麻烦。
好在最新的HTML5中加入了WebSocket协议,我们可以通WebSocket这种基于HTTP协议之上的即时通信协议来替代ajax这种传统的我问你答的老旧通信模式。而我们是PHPer,对付我们这种只懂PHP的人该如何编写WebSocket做事端呢?好在我们又得知PHP有一个Swoole扩展,我们在PHP措辞中利用它可以很方便的构建一个WebSocket做事端。
关于Swoole,下面这段是其官网上的话:
PHP的异步、并行、高性能网络通信引擎,利用纯C措辞编写,供应了PHP措辞的异步多线程做事器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,行列步队,毫秒定时器,异步文件读写,异步DNS查询。Swoole内置了Http/WebSocket做事器端/客户端、Http2.0做事器端。
Swoole可以广泛运用于互联网、移动通信、企业软件、云打算、网络游戏、物联网(IOT)、车联网、智能家居等领域。利用PHP+Swoole作为网络通信框架,可以使企业IT研发团队的效率大大提升,更加专注于开拓创新产品。
还有一个问题须要办理,那便是,这个jquery.danmu.js是基于弹幕运行韶光的一个插件。那又要如何做到实时呢。开始博主想的是在做事器端规定一个韶光(即其连接韶光),当有客户端连接时,返回做事器确当前韶光戳,然后以此为依据开始计时。但是碰着的问题如下:
该弹幕插件是按十分之秒计时制度。
各浏览器上js的定时器的运行韶光略有差异。
韶光不能完备同步。
websocket是实时通信的,哎,那所有客户真个韶光,不一致就不一致吧,弹幕发的韶光根据各个客户真个为准呗,都以当前各个客户真个韶光来发,websocket只通报不包含韶光的数据(好吧有点绕,我自己都觉得说饶了),咱们直接来上代码吧。
index.html
<!DOCTYPEhtml>
<htmllang=\公众en\"大众>
<head>
<metacharset=\"大众utf-8\"大众>
<metaname=\公众viewport\"大众content=\"大众width=device-width,initial-scale=1.0\"大众>
<title>弹幕madebydiligentyang</title>
<style>
body{
font-family:\"大众MicrosoftYaHei\"大众!important;
font-color:#222;
}
pre{
line-height:2em;
font-family:\"大众MicrosoftYaHei\公众!important;
}
h4{
line-height:2em;
}
#danmuarea{
position:relative;
background:#222;
width:800px;
height:445px;
margin-left:auto;
margin-right:auto;
}
.center{
text-align:center;
}
.ctr{
font-size:1em;
line-height:2em;
}
</style>
<scriptsrc=\公众http://libs.baidu.com/jquery/2.1.4/jquery.min.js\"大众></script>
<scriptsrc=\"大众../dist/jquery.danmu.min.js\"大众></script>
</head>
<bodyclass=\"大众center\公众>
Demo<br><br>
<!--黑背景和弹幕区-->
<divid=\"大众danmuarea\"大众>
<divid=\公众danmu\公众>
</div>
</div>
<!--掌握区-->
<divclass=\"大众ctr\"大众>
<buttontype=\公众button\"大众onclick=\公众pauser()\公众>弹幕停息</button>
<buttontype=\公众button\"大众onclick=\公众resumer()\公众>弹幕连续</button>
显示弹幕:<inputtype='checkbox'checked='checked'id='ishide'value='is'onchange='changehide()'>
弹幕透明度:
<inputtype=\"大众range\"大众name=\"大众op\公众id=\"大众op\"大众onchange=\公众op()\公众value=\"大众100\"大众><br>
当前弹幕运行韶光(秒):<spanid=\公众time\"大众></span>
<!--设置当前弹幕韶光(秒):<inputtype=\公众text\公众id=\"大众set_time\"大众max=20/>
<buttontype=\"大众button\公众onclick=\公众settime()\"大众>设置</button>-->
<br>
发弹幕:
<selectname=\"大众color\"大众id=\"大众color\"大众>
<optionvalue=\公众white\公众>白色</option>
<optionvalue=\公众red\公众>赤色</option>
<optionvalue=\"大众green\"大众>绿色</option>
<optionvalue=\公众blue\公众>蓝色</option>
<optionvalue=\公众yellow\"大众>黄色</option>
</select>
<selectname=\公众size\"大众id=\"大众text_size\"大众>
<optionvalue=\"大众1\"大众>大笔墨</option>
<optionvalue=\"大众0\"大众>小笔墨</option>
</select>
<selectname=\公众position\"大众id=\公众position\"大众>
<optionvalue=\"大众0\"大众>滚动</option>
<optionvalue=\公众1\公众>顶端</option>
<optionvalue=\"大众2\"大众>底端</option>
</select>
<inputtype=\公众textarea\公众id=\"大众text\公众max=300/>
<buttontype=\"大众button\"大众onclick=\"大众send()\"大众>发送</button>
</div>
<script>
//WebSocket
varwsServer='ws://123.206.61.229:9505';
varwebsocket=newWebSocket(wsServer);
websocket.onopen=function(evt){
console.log(\"大众ConnectedtoWebSocketserver.\"大众);
/websocket.send(\"大众gaga\"大众);/
//连上之后就打开弹幕
$('#danmu').danmu('danmuResume');
};
websocket.onclose=function(evt){
console.log(\公众Disconnected\公众);
};
websocket.onmessage=function(evt){
console.log('Retrieveddatafromserver:'+evt.data);
vartime=$('#danmu').data(\"大众nowTime\公众)+1;
vartext_obj=evt.data+',\"大众time\公众:'+time+'}';//获取加上当前韶光
console.log(text_obj);
varnew_obj=eval('('+text_obj+')');
$('#danmu').danmu(\公众addDanmu\"大众,new_obj);//添加弹幕
};
websocket.onerror=function(evt,e){
console.log('Erroroccured:'+evt.data);
};
//初始化
$(\"大众#danmu\"大众).danmu({
left:0,
top:0,
height:\"大众100%\"大众,
width:\"大众100%\"大众,
speed:20000,
opacity:1,
font_size_small:16,
font_size_big:24,
top_botton_danmu_time:6000
});
//一个定时器,监视弹幕韶光并更新到页面上
functiontimedCount(){
$(\"大众#time\"大众).text($('#danmu').data(\公众nowTime\"大众));
t=setTimeout(\"大众timedCount()\公众,50)
}
timedCount();
functionstarter(){
$('#danmu').danmu('danmuStart');
}
functionpauser(){
$('#danmu').danmu('danmuPause');
}
functionresumer(){
$('#danmu').danmu('danmuResume');
}
functionstoper(){
$('#danmu').danmu('danmuStop');
}
functiongetime(){
alert($('#danmu').data(\"大众nowTime\公众));
}
functiongetpaused(){
alert($('#danmu').data(\"大众paused\公众));
}
//发送弹幕,利用了文档README.md第7节中推举的方法
functionsend(){
vartext=document.getElementById('text').value;
varcolor=document.getElementById('color').value;
varposition=document.getElementById('position').value;
//vartime=$('#danmu').data(\公众nowTime\"大众)+1;
varsize=document.getElementById('text_size').value;
//vartext_obj='{\公众text\"大众:\公众'+text+'\"大众,\"大众color\公众:\公众'+color+'\"大众,\公众size\"大众:\"大众'+size+'\"大众,\"大众position\"大众:\公众'+position+'\"大众,\公众time\"大众:'+time+'}';
//为了处理大略,方便后续加time,和isnew,就先酱紫发一半吧。
//注:time为弹幕出来的韶光,isnew为是否加边框,自己发的弹幕,常理上来说是有边框的。
vartext_obj='{\公众text\"大众:\公众'+text+'\"大众,\公众color\公众:\"大众'+color+'\"大众,\"大众size\"大众:\"大众'+size+'\公众,\"大众position\"大众:\"大众'+position+'\公众';
//利用websocket发送
websocket.send(text_obj);
//清空相应的内容
document.getElementById('text').value='';
}
//调度透明度函数
functionop(){
varop=document.getElementById('op').value;
$('#danmu').danmu(\"大众setOpacity\"大众,op/100);
}
//调隐蔽显示
functionchangehide(){
varop=document.getElementById('op').value;
op=op/100;
if(document.getElementById(\"大众ishide\"大众).checked){
$(\公众#danmu\公众).danmu(\"大众setOpacity\公众,1)
}else{
$(\公众#danmu\"大众).danmu(\"大众setOpacity\"大众,0)
}
}
//设置弹幕韶光
functionsettime(){
vart=document.getElementById(\"大众set_time\"大众).value;
t=parseInt(t)
$('#danmu').danmu(\"大众setTime\"大众,t);
}
</script>
</body>
</html>
上述代码须要把稳的是websocket的建立和吸收,以及send方法中对弹幕的处理。
ws_server.php
<?php
//创建websocket做事器工具,监听0.0.0.0:9505端口
$ws=newswoole_websocket_server(\公众0.0.0.0\公众,9505);
//监听WebSocket连接打开事宜
$ws->on('open',function($ws,$request){
//var_dump($request->fd,$request->get,$request->server);
//相称于记录一个日志吧,有连接韶光和连接ip
echo$request->fd.'-----time:'.date(\"大众Y-m-dH:i:s\"大众,$request->server['request_time']).'--IP--'.$request->server['remote_addr'].'-----';
});
//监听WebSocket事宜
$ws->on('message',function($ws,$frame){
//记录收到的,可以写到日志文件中
echo\"大众Message:{$frame->data}\n\"大众;
//遍历所有连接,循环广播
foreach($ws->connectionsas$fd){
//如果是某个客户端,自己发的则加上isnew属性,否则不加
if($frame->fd==$fd){
$ws->push($frame->fd,$frame->data.',\"大众isnew\公众:\"大众\"大众');
}else{
$ws->push($fd,\公众{$frame->data}\公众);
}
}
});
//监听WebSocket连接关闭事宜
$ws->on('close',function($ws,$fd){
echo\公众client-{$fd}isclosed\n\"大众;
});
$ws->start();
运行方法:
输入phpws_server.php先启动做事器真个websocket。如果要后台运行,且不随用户终端关闭而断开,须要创建一个log.txt用于存取上述输出的东西,然后输入nohupphpws_server.php>log.txt&即可。
注,如果要用此项目,须要自行修正自己的做事器ip地址。只须要修正varwsServer='ws://123.206.61.229:9505';处即可,后台代码不须要做任何处理。
末了希望对同学们有所帮助。想要学习PHP开拓技能的小伙伴欢迎选择扣丁学堂进行学习。扣丁学堂不仅有专业的老师和与时俱进的课程体系,还有大量的PHP视频教程供学员不雅观看学习,想要学到实用技能高薪就业的小伙伴抓紧韶光行动吧。扣丁学堂PHP技能互换群:374332265。