/** * Websocket handshake. * @param string $buffer * @param TcpConnection $connection * @return int */ protected static function dealHandshake($buffer, $connection) { // HTTP protocol. if (0 === strpos($buffer, 'GET')) { // Find \r\n\r\n. $heder_end_pos = strpos($buffer, "\r\n\r\n"); if (!$heder_end_pos) { return 0; } // Get Sec-WebSocket-Key. $Sec_WebSocket_Key = ''; if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Sec-WebSocket-Key not found.<br>This is a WebSocket service and can not be accessed via HTTP.", true); $connection->close(); return 0; } // Calculation websocket key. $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // Handshake response data. $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"; $handshake_message .= "Upgrade: websocket\r\n"; $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; $handshake_message .= "Connection: Upgrade\r\n"; $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; // Mark handshake complete.. $connection->websocketHandshake = true; // Websocket data buffer. $connection->websocketDataBuffer = ''; // Current websocket frame length. $connection->websocketCurrentFrameLength = 0; // Current websocket frame data. $connection->websocketCurrentFrameBuffer = ''; // Consume handshake data. $connection->consumeRecvBuffer(strlen($buffer)); // Send handshake response. $connection->send($handshake_message, true); // There are data waiting to be sent. if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } // blob or arraybuffer if (empty($connection->websocketType)) { $connection->websocketType = self::BINARY_TYPE_BLOB; } // Try to emit onWebSocketConnect callback. if (isset($connection->onWebSocketConnect)) { self::parseHttpHeader($buffer); try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { echo $e; exit(250); } $_GET = $_COOKIE = $_SERVER = array(); } return 0; } elseif (0 === strpos($buffer, '<polic')) { $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . ""; $connection->send($policy_xml, true); $connection->consumeRecvBuffer(strlen($buffer)); return 0; } // Bad websocket handshake request. $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Invalid handshake data for websocket. ", true); $connection->close(); return 0; }
/** * 处理websocket握手 * @param string $buffer * @param TcpConnection $connection * @return int */ protected static function dealHandshake($buffer, $connection) { // 握手阶段客户端发送HTTP协议 if (0 === strpos($buffer, 'GET')) { // 判断\r\n\r\n边界 $heder_end_pos = strpos($buffer, "\r\n\r\n"); if (!$heder_end_pos) { return 0; } // 解析Sec-WebSocket-Key $Sec_WebSocket_Key = ''; if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // 握手返回的数据 $new_message = "HTTP/1.1 101 Switching Protocols\r\n"; $new_message .= "Upgrade: websocket\r\n"; $new_message .= "Sec-WebSocket-Version: 13\r\n"; $new_message .= "Connection: Upgrade\r\n"; $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; $connection->handshake = true; $connection->consumeRecvBuffer(strlen($buffer)); $connection->send($new_message, true); $connection->protocolData = array('binaryType' => self::BINARY_TYPE_BLOB); // 如果有设置onWebSocketConnect回调,尝试执行 if (isset($connection->onWebSocketConnect)) { self::parseHttpHeader($buffer); try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { echo $e; } $_GET = $_COOKIE = $_SERVER = array(); } return 0; } elseif (0 === strpos($buffer, '<polic')) { if ('>' != $buffer[strlen($buffer) - 1]) { return 0; } $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . ""; $connection->send($policy_xml, true); $connection->consumeRecvBuffer(strlen($buffer)); return 0; } // 出错 $connection->close(); return 0; }
/** * 处理websocket握手 * @param string $buffer * @param TcpConnection $connection * @return int */ protected static function dealHandshake($buffer, $connection) { // 握手阶段客户端发送HTTP协议 if (0 === strpos($buffer, 'GET')) { // 判断\r\n\r\n边界 $heder_end_pos = strpos($buffer, "\r\n\r\n"); if (!$heder_end_pos) { return 0; } // 解析Sec-WebSocket-Key $Sec_WebSocket_Key = ''; if (preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/", $buffer, $match)) { $Sec_WebSocket_Key = $match[1]; } else { $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Sec-WebSocket-Key not found", true); $connection->close(); return 0; } // 握手的key $new_key = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true)); // 握手返回的数据 $handshake_message = "HTTP/1.1 101 Switching Protocols\r\n"; $handshake_message .= "Upgrade: websocket\r\n"; $handshake_message .= "Sec-WebSocket-Version: 13\r\n"; $handshake_message .= "Connection: Upgrade\r\n"; $handshake_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n"; // 标记已经握手 $connection->websocketHandshake = true; // 缓冲fin为0的包,直到fin为1 $connection->websocketDataBuffer = ''; // 当前数据帧的长度,可能是fin为0的帧,也可能是fin为1的帧 $connection->websocketCurrentFrameLength = 0; // 当前帧的数据缓冲 $connection->websocketCurrentFrameBuffer = ''; // 消费掉握手数据,不触发onMessage $connection->consumeRecvBuffer(strlen($buffer)); // 发送握手数据 $connection->send($handshake_message, true); // 握手后有数据要发送 if (!empty($connection->tmpWebsocketData)) { $connection->send($connection->tmpWebsocketData, true); $connection->tmpWebsocketData = ''; } // blob or arraybuffer $connection->websocketType = self::BINARY_TYPE_BLOB; // 如果有设置onWebSocketConnect回调,尝试执行 if (isset($connection->onWebSocketConnect)) { self::parseHttpHeader($buffer); try { call_user_func($connection->onWebSocketConnect, $connection, $buffer); } catch (\Exception $e) { echo $e; } $_GET = $_COOKIE = $_SERVER = array(); } return 0; } elseif (0 === strpos($buffer, '<polic')) { $policy_xml = '<?xml version="1.0"?><cross-domain-policy><site-control permitted-cross-domain-policies="all"/><allow-access-from domain="*" to-ports="*"/></cross-domain-policy>' . ""; $connection->send($policy_xml, true); $connection->consumeRecvBuffer(strlen($buffer)); return 0; } // 出错 $connection->send("HTTP/1.1 400 Bad Request\r\n\r\n<b>400 Bad Request</b><br>Invalid handshake data for websocket. ", true); $connection->close(); return 0; }