握手函数doHandShake:
function doHandShake($socketId){
//一旦进入了doHandshake函数,说明已收到完整的请求头,故将此socketId从handshakingList中移除
array_splice($this->handshakingList, array_search($socketId, $this->handshakingList), 1);
//获取socket的相关信息
$session = $this->socketListMap[$socketId];
//获取http请求头
$headers = $this->getHeaders($session['buffer']);
//请求的数据内容会清空,因为已经读取过了,这里buffer是一个读取缓冲区
$this->socketListMap[$socketId]['buffer'] = '';
$this->socketListMap[$socketId]['headers'] = $headers;
//checkBaseHeader用于检查基本头信息,如果有任何一个头信息不符合WebSocket协议,则检查失败
//checkCustomHeader为用户自定义头部检查,需要继承类覆盖实现,一般检查cookie、origin等与业务相关的头部信息
if (!$this->checkBaseHeader($headers) || !$this->checkCustomHeader($headers)) {
//生成握手失败响应
$this->badRequest($socketId);
//关闭连接
$this->disconnect($socketId);
//握手失败回调
$this->onHandShakeFailure($socketId);
return false;
} else {
//获取握手返回头部数据
$responseHeader = $this->getHandShakeHeader($headers);
}
//发送响应头
$this->socketSend($socketId, $responseHeader);
//已握手标记置为true,之后在收到该socket数据将进入数据处理逻辑
$this->socketListMap[$socketId]['handshake'] = true;
//握手成功回调
$this->onHandShakeSuccess($socketId);
}
checkBaseHeader函数:
function checkBaseHeader($header) {
//检查Upgrade字段是否为websocket
return strcasecmp($header['Upgrade'], 'websocket') === 0 &&
//检查Connection字段是否为Upgrade
strcasecmp($header['Connection'], 'Upgrade') === 0 &&
//检查Sec-WebSocket-Key字段Base64解码后长度是否为16字节
strlen(base64_decode($header['Sec-WebSocket-Key'])) === 16 &&
//检查WebSocket协议版本是否为13,该类仅处理版本为13的WebSocket协议
$header['Sec-WebSocket-Version'] === '13';
}
badRequest函数:
function badRequest($socketId) {
//该函数仅拼装握手错误的响应信息,并发送
$message = 'This is a websocket server!';
$out = "HTTP/1.1 400 Bad request\n";
$out .= "Server: WebSocket Server/lyz810\n";
$out .= "Content-Length: " . strlen($message) . "\n";
$out .= "Connection: close\n\n";
$out .= $message;
$this->socketSend($socketId, $out);
}
getHandShakeHeader函数:
function getHandShakeHeader($headers) {
//拼装响应头的相关字段
$responseHeader = array(
'HTTP/1.1 101 Switching Protocols',
'Upgrade: WebSocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: ' . $this->getWebSocketAccept($headers['Sec-WebSocket-Key']),
);
if (isset($headers['Sec-WebSocket-Protocol'])) {
//子协议选择,应由继承类覆盖实现,否则默认使用最先出现的子协议
$protocol = $this->selectProtocol(explode(',', $headers['Sec-WebSocket-Protocol']));
array_push($responseHeader, 'Sec-WebSocket-Protocol: ' . $protocol);
}
return implode("\r\n", $responseHeader) . "\r\n\r\n";
}
getWebSocketAccept函数:
function getWebSocketAccept($websocketKey) {
//根据协议要求,计算WebSocket-accept-key
return base64_encode(sha1($websocketKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
}