我们使用PHP带的socket扩展开发聊天室的时候,很多人不会升级协议、解帧和封帧,下面我们就把这些东西写一下做个记录。
协议升级
websocket链接到服务端以后需要把协议从http升级到websocket,这个时候我们就需要获取请求中的Sec-WebSocket-Key的值拿到,我们使用PHP自带的preg_match获取即可,代码如下
preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match)里面的参数都是什么意思,我就不做讲解了。我们获取到这个Sec-WebSocket-Key后,组装响应完成升级,代码如下
preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $buffer, $match);
$responseKey = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"Sec-WebSocket-Accept: " . $responseKey . "\r\n\r\n";
然后发送给客户端即可完成协议升级。
解帧
public function decode($buffer)
{
$len = $masks = $data = $decoded = null;
$len = ord($buffer[1]) & 127;
if ($len === 126) {
$masks = substr($buffer, 4, 4);
$data = substr($buffer, 8);
} elseif ($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++) {
$decoded .= $data[$index] ^ $masks[$index % 4];
}
return $decoded;
}
封帧
public function frame($message)
{
$len = strlen($message);
if ($len <= 125) {
return "\x81" . chr($len) . $message;
} else if ($len <= 65535) {
return "\x81" . chr(126) . pack("n", $len) . $message;
} else {
return "\x81" . char(127) . pack("xxxxN", $len) . $message;
}
}
代码具体什么意思,这里就不再做过多的讲解了,相信大家也是可以看明白的。