手机版

php使用websocket示例的详细说明

时间:2021-11-09 来源:互联网 编辑:宝哥软件园 浏览:

我在下面画了一个图来演示在客户端和服务器之间建立websocket连接时的握手部分,这可以在node中轻松完成,因为node提供的net模块已经封装了socket socket,开发者在使用时只需要考虑数据交互,而不需要考虑连接的建立。然而,php没有。我们需要从socket的连接、建立、绑定、监控等方面自己操作,所以有必要拿出来再谈。

(1)和(2)实际上是一个HTTP请求和响应,但是我们在处理过程中得到的是一个未解析的字符串。例如,复制代码如下: get/chat http/1.1 host : server . example . co origin 3360 http://www.jb51.com。我们总是看到的要求是这样的。当这个东西到达服务器时,我们可以通过一些代码库直接获取这个信息。1.php中websocketWebSocket连接的处理是由客户端发起的,所以一切都应该从客户端开始。第一步是解析客户端发送的安全套接字密钥字符串。复制代码如下: get/Chat HTTP/1.1 host : server . example.comupgrade : WebSocket connection : UpgradeSec-web socket-key : dghlihnhbxbszsbbub 25 jzq==origin : http://www.jb51.co MSEC的格式-web socket-Protocol 3: Chat,Super ChatSec-web socket-Version : 13客户端请求。首先,php建立一个套接字连接并监控端口信息。1.socket Connection的建立关于Socket Socket的建立,相信很多在大学学过计算机网络的人都知道。以下是连接建立过程:

复制代码代码如下://建立一个窝套接字$master=socket_create(AF_INET,SOCK_STREAM,SOL _ TCP);socket_set_option($master,SOL_SOCKET,SO _ REUSEADDR,1);socket_bind($master,$address,$ port);socket _ listen($ master);相比节点,这个地方的处理实在是太麻烦了,上面几行代码并未建立连接,只不过这些代码是建立一个窝套接字必须要写的东西。由于处理过程稍微有复杂,所以我把各种处理写进了一个类中,方便管理和调用。复制代码代码如下://演示。phpclass WS { var $ master//连接计算机网络服务器的client var $ sockets=array();//不同状态的窝管理var $ handshake=false//判断是否握手function __construct($address,$port){ //建立一个窝套接字$ this-master=socket _ create(AF _ INET,SOCK_STREAM,SOL_TCP)或芯片(' socket_create()'失败');socket_set_option($this-master,SOL_SOCKET,SO_REUSEADDR,1)或芯片(' socket_option())失败);socket_bind($this-master,$address,$port)或芯片(' socket_bind()'失败');socket_listen($this-master,2)或die('socket_listen()'失败');$ this-sockets[]=$ this-master;//调试回应('主套接字: '。$这个-主人\\ n ');while(true) { //自动选择来消息的窝如果是握手自动选择主机$ write=NULL $ except=NULLsocket _ select($ this-sockets,$ write,$ except,NULL);foreach($ this-socket as $ socket){//连接主机的client if($ socket==$ this-master){ $ client=socket _ accept($ this-master);if($ client 0){//debug echo“socket _ accept()”失败;继续;} else {//connect($ client);array_push($this-sockets,$ client);回显"连接客户端\ n ";} } else { $ bytes=@ socket _ recv($ socket,$buffer,2048,0);if($bytes==0)返回;if(!$this-handshake) { //如果没有握手,先握手回应//doHandShake($socket,$ buffer);回显“ShakeHands \ n”;} else { //如果已经握手,直接接受数据,并处理$ buffer=decode($ buffer);//进程($socket,$ buffer);回显"发送文件\ n ";} } } } }}上面这段代码是经过我调试了的,没太大的问题,如果想测试的话,可以在煤矿管理局命令行中键入PHP/路径/到/演示。PHP当然,上面只是一个类,如果要测试的话,还得新建一个实例。复制代码代码如下:$ws=new WS('localhost ',4000);客户端代码可以稍微简单点:复制代码代码如下: var ws=new WebSocket(' ws ://localhost :4000 ');ws。onopen=function(){ console。日志('握手成功');};ws。onerror=function(){ console。日志('错误');};运行服务器代码,当客户端连接的时候,我们可以看到

2.提取秒-网络套接字-密钥信息复制代码代码如下:函数GetKey($ req){ $ Key=null;if(preg _ match('/Sec-WebSocket-Key :(.*)\r\n/',$req,$ match)){ $ key=$ match[1];}返回$ key}这里比较简单,直接正则匹配,websocket信息头一定包含秒-网络套接字-密钥,所以我们匹配起来也比较快捷~3.加密秒-网络套接字-密钥复制代码代码如下:函数encryy($ req){ $ key=$ this-getKey($ req);$ mask=' 258 eafa 5-E914-47DA-95CA-c5ab 0dc 85b 11 ';返回base64_encode(sha1($key .258 eafa 5-E914-47DA-95CA-c5ab 0dc 85b 11 ',真);}将SHA-1加密后的字符串再进行一次base64加密。如果加密算法错误,客户端在进行校检的时候会直接报错

4.应答秒-网络套接字-接受复制代码代码如下:函数do handshake($ socket,$req){ //获取加密key $ accept key=$ this-encryy($ req);$upgrade='HTTP/1.1 101交换协议\r\n ' .Upgrade: websocket\r\n ' .连接:升级\r\n ' .Sec-WebSocket-Accept: ' .$acceptKey .\r\n .\ r \ n ';//写入socket socket_write(socket,$upgrade.chr(0),strlen($ upgrade。chr(0)));//标记握手已经成功,下次接受数据采用数据帧格式$这个-握手=true}这里千万要注意,每一个请求和相应的格式,最后有一个空行,也就是\r\n,开始测试的时候把这东西给弄丢了,纠结了半天

当客户端成功校检键后,会触发onopen函数

5.数据帧处理复制代码代码如下://解析数据帧函数decode($ buffer){ $ len=$ masks=$ data=$ decode=null;$ len=order($ buffer[1])127;if($ len===126){ $ masks=substr($ buffer,4,4);$data=substr($buffer,8);} else if($ len===127){ $ masks=substr($ buffer,10,4);$data=substr($buffer,14);} else { $masks=substr($buffer,2,4);$data=substr($buffer,6);} for($ index=0;$ index strlen($ data);$ index){ $已解码=$ data[$ index]^ $ masks[$ index % 4];}返回$ decoded }这里涉及的编码问题在前文中已经提到过了,这里就不赘述,php对字符处理的函数太多了,也记得不是特别清楚,这里就没有详细的介绍解码程序,直接把客户端发送的数据原样返回,可以算是一个聊天室的模式吧。复制代码代码如下://返回帧信息处理函数框架($s) { $a=str_split($s,125);if(count($ a)=1){ return ' \ x81 ' .chr(strlen($a[0]).$ a[0];} $ ns=foreach ($a as $o) { $ns .='\x81 ' .人权委员会(strlen(o)).$ o;}返回$ ns}//返回数据函数send($client,$ msg){ $ msg=$ this-frame($ msg);socket_write($client,$msg,strlen($ msg));}客户端代码:复制代码代码如下: var ws=new WebSocket(' ws ://localhost :4000 ');ws。onopen=function(){ console。日志('握手成功');};ws。on消息=函数(e){控制台。日志('消息: ' e . data);};ws。onerror=function(){ console。日志('错误');};ws.send('李靖');在连通之后发送数据,服务器原样返回

二、注意问题1.websocket版本问题客户端在握手时的请求中有sec-WebSocket-版本: 13,这样的版本标识,这个是一个升级版本,现在的浏览器都是使用的这个版本。而以前的版本在数据加密的部分更加麻烦,它会发送两个密钥:复制代码代码如下: get/chat HTTP/1.1主机:服务器。例子。com升级: web socket连接:升级原点://www。JB 51。netsec-web套接字-协议:聊天,Supchatsec-web套接字-密钥1: xxxx sec-web套接字-密钥2: xxxx如果是这种版本(比较老,已经没在使用了),需要通过下面的方式获取复制代码代码如下:function encry($key1,$key2,$ l8b){//获取数字preg_match_all('/([\d] )/',$key1,$ key 1 _ num);preg_match_all('/([\d] )/',$key2,$ key 2 _ num);$ key 1 _ num=inter decd($ key 1 _ num[0]);$ key 2 _ num=inter decd($ key 2 _ num[0]);//计数空格preg _ match _ all('/([])/',$key1,$ key 1 _ SPC);preg_match_all('/([ ] )/',$key2,$ key 2 _ SPC);if($ key 1 _ SPC==0 | $ key 2 _ SPC==0){ $ this-log('无效键');返回;}//某些数学$key1_sec=pack('N ',$ key 1 _ num/$ key 1 _ SPC);$key2_sec=pack('N ',$ key 2 _ num/$ key 2 _ SPC);返回md5($key1_sec).$key2_sec .$ l8b,1);}只能无限吐槽这种验证方式!相比nodeJs的websocket操作方式:复制代码代码如下://服务器程序var crypto=require(' crypto ');var WS=' 258 eafa 5-E914-47DA-95CA-c5ab 0dc 85b 11 ';需要(“净”).createServer(function(o){ var key;o.on('数据',函数(e){if(!key){//握手key=e.toString().匹配(/Sec-WebSocket-Key:(.)/)[1];key=crypto.createHash('sha1 ').更新(密钥WS ).摘要(“base64”);o.write('HTTP/1.1 101交换协议\ r \ n ');o . write('升级: web套接字\ r \ n ');o.write('Connection:升级\ r \ n ');o . write(' Sec-WebSocket-accept : ' key ' \ r \ n ');o . write(' \ r \ n ');} else { console。日志(e);};});}).听(8000);2.数据帧解析代码本文没有给出解码帧这样数据帧解析代码,前文中给出了数据帧的格式,解析纯属体力活。

版权声明:php使用websocket示例的详细说明是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。