本次教程需要理解的内容:
什么是WebSocket?
WebSocket可以用来干什么?
什么是WebSocket握手?
php使用WebSocket的流程?
php中WebSocket相关函数的作用?
(一)什么是WebSocket?
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
(二)WebSocket的作用?
WebSock其实在平常使用,我们是时常见到的,用于实时通讯,例如我们常用的实时聊天、服务端向客户端消息推送、也可以实现踢用户下线功能。实时弹幕功能等等。
(三)什么是握手?
为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。
这是比较正式的理解,在接下来使用方式中会在介绍到握手的实际含义。
(四)php使用WebSocket的流程及相关函数的意义
这里代码注释都会进行逐一解释,所以就直接上代码,有什么不懂欢迎提出来。
1: 则最多在n秒后结束,如遇某一个连接有新动态,则提前返回
* 如果为null:如遇某一个连接有新动态,则返回
*/
socket_select($changes,$write,$except,NULL);
//这里遍历检测出出现何种变化,然后进行处理
foreach($changes as $sock){
//当下列条件的满足时,表示有新用户连接进来
if($sock==$master){
//接受该用户的连接
$client=socket_accept($master);
//给这个用户生成一个独一无二的id,用与获取该用户的信息的唯一标识。
$key=uniqid();
//将新用户存入socke连接池
$sockets[]=$client;
//记录用户连接的信息,为了方便能对指定用户发送消息。其中handshake代表服务器与客户端握手与否,socket的另外一个重要的操作
$users[$key]=array(
"socket"=>$client,
"handshake"=>false,
);
echo "分配id为".$key."的用户连接\n";
}
// 剩下的为用户断开连接或者用户向服务端发送信息
else{
$len=0;//收到数据的长度
$buffer='';//收到的数据
/**
* socket_recv( resource $socket, string &$buf, int $len, int $flags) : int
* 函数 socket_recv() 从 socket 中接受长度为 最大为$len 字节的数据,并保存在 buf 中,$l返回的为实际读取数据的长度。
* socket_recv() 用于从已连接的socket中接收数据。除此之外,可以设定一个或多个 flags 来控制函数的具体行为。
*/
//通过循环的方式读取全部数据$len可根据自身设置
do{
$l=socket_recv($sock,$buf,1000,0);
$len+=$l;
$buffer.=$buf;
}while($l==1000);
$tmpk;//获取操作用户的key,即一开始分配的唯一标识id
foreach($users as $k=>$v){//$k为键,$v为值
if($sock==$v['socket']){
//获取连接的用户数组users,当users里存在有只返回该用户被分配的唯一id
$tmpk=$k;
}
}
// 如果数据长度小于7为断开连接
if($len<7){
socket_close($users[$k]['socket']);//关闭该用户连接,可以写成socket_close($sock),这种写法是封装后的写法,为了容易看懂不进行封装;
unset($users[$tmpk]);//销毁指定的users的某个用户信息
$sockets=array($master);//可以理解为初始化sockets连接池
//遍历users数组,将连接的信息存入$sockets中
foreach($users as $v){
$sockets[]=$v['socket'];
}
echo "id为".$tmpk."用户断开连接\n";
continue;
}
//服务端与用户握手
//如果没有与客户端握手,数据交换都会错误。
//一旦服务器发送了以下头文件,握手就完成了,我们就可以交换数据了,可以理解为检验身份差不多的意思
if(!$users[$tmpk]['handshake']){
//截取客户端请求时发送给服务端Sec-WebSocket-Key的值并加密,其中$key后面的一部分258EAFA5-E914-47DA-95CA-C5AB0DC85B11字符串应该是固定的
$buf = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
$key=trim(substr($buf,0,strpos($buf,"\r\n")));//前两步可以直接替换为trim(substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+16))
$new_key=base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
//向客户端返回该信息,也就是所说的握手。
$hand_message="HTTP/1.1 101 Switching Protocols\r\n"
."Upgrade: websocket\r\n"
."Sec-Websocket-Version: 13\r\n"
."Connection: Upgrade\r\n"
."Sec-Websocket-Accept: ".$new_key."\r\n\r\n";
/**
* writes to the socket from the given buffer
* 向指定的socket发送信息
* 这里向用户发送握手信息
*/
$status=socket_write($users[$tmpk]['socket'],$hand_message,strlen($hand_message));
if($status){
echo "与用户id".$tmpk."握手成功\n";
echo $hand_message."\n";
}
}
// 最后剩下的就为用户发送消息,做接收操作,由于需要包含二进制数据的转换,需了解websocket的数据收发协议,下一篇将更新接下来数据的处理
else{
//接收数据处理操作
}
}
}
}
?>
结语:由于接下来数据的接收与发送,会涉及到数据的解码与编码,下一篇内容将会介绍数据的发送与接收,对各个操作都详细的解释。
自己学习过程中没看到叫详细的教程,就写个专题关于WebSocket的使用,当然也可以使用workman等开源通讯框架,少去很多麻烦,在这里也是为了构造自己的通讯方式,自己编写。
有兴趣的持续关注之后将会更新的内容。