客户端无法收到握手信息

original

想写一下websocket,但是无论如何收不到捂手信息,找了好久,有人给瞅瞅吗,chrome一直显示pending,代码如下:

$address = '0.0.0.0';

$port = '8081';

$sockets = [];

$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);

socket_bind($server, $address, $port);

socket_listen($server, 10);

array_push($sockets, $server);

while (true) {
    $write = null;
    $except = null;
    socket_select($sockets, $write, $except, null);
    foreach ($sockets as $socket) {
        if ($socket == $server) {
            //等待接受一个链接
            $client = socket_accept($socket);

            //获取接数据
            $buff = socket_read($client, 1024);

            //得到请求头中升级ws协议的key
            preg_match('/Sec\-WebSocket\-Key:\s(.*)/', $buff, $result);
            $wsKey = $result;

            //编码key 编码方式: 请求头Sec-WebSocket-Key的值 + 固定字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" sha1进行hash后base64编码
            $acceptWsKey = base64_encode(pack('H*', sha1($wsKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));

            //组合响应头
            $responseHttpHeader = 'HTTP/1.1 101 Switching Protocols\r\n';
            $responseHttpHeader .= 'Upgrade: websocket\r\n';
            $responseHttpHeader .= 'Connection: Upgrade\r\n';
            $responseHttpHeader .= 'Sec-WebSocket-Accept: ' . $acceptWsKey . '\r\n\r\n';
            socket_write($client, $responseHttpHeader, strlen($responseHttpHeader));
            array_push($sockets, $client);
        }
    }
}
3408 2 0
2个回答

original

最近正在学习socket   如果问的有点低级 大佬别喷...   

  • 暂无评论
blogdaren
  1. 握手期间参考代码:
<?php
$address = '0.0.0.0';
$port = '8081';
$mainSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($mainSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($mainSocket, $address, $port);
socket_listen($mainSocket, 10);
$read_socks[] = $mainSocket;
$write_socks =  array();
$except_socks = NULL;  

while(1)
{
    $tmp_reads = $read_socks;
    $tmp_writes = $write_socks;
    $select_result = @socket_select($tmp_reads, $tmp_writes, $except_socks, NULL);  
    if(false === $select_result) continue;

    foreach($tmp_reads as $read)
    {
        if($read == $mainSocket)
        {
            $new_socket = @socket_accept($mainSocket);
            if(!$new_socket) continue;
            $read_socks[] = $new_socket;
            $write_socks[] = $new_socket;
        }
        else
        {
            $msg = socket_read($read, 1024);
            if($msg === '')
            {
                foreach($read_socks as $k => $v)
                {
                    if($v == $read) unset($read_socks);
                }

                foreach($write_socks as $k => $v)
                {
                    if($v == $read) unset($write_socks);
                }
                socket_close($read);
            }
            else
            {
                //得到请求头中升级ws协议的key
                if(!preg_match("/Sec-WebSocket-Key: *(.*?)\r\n/i", $msg, $match)) throw new \Exception('bad request');
                $Sec_WebSocket_Key = $match;

                //编码key 编码方式: 请求头Sec-WebSocket-Key的值 + 固定字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11" sha1进行hash后base64编码
                $acceptWsKey = base64_encode(sha1($Sec_WebSocket_Key . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", true));

                //组合响应头
                if(in_array($read, $tmp_writes))
                {
                    $responseHttpHeader  = "HTTP/1.1 101 Switching Protocols\r\n";
                    $responseHttpHeader .= "Upgrade: websocket\r\n";
                    $responseHttpHeader .= "Sec-WebSocket-Version: 13\r\n";
                    $responseHttpHeader .= "Connection: Upgrade\r\n";
                    $responseHttpHeader .= "Sec-WebSocket-Accept: " . $acceptWsKey . "\r\n\r\n";
                    socket_write($read, $responseHttpHeader, strlen($responseHttpHeader));
                }
            }
        }
    }
}
  1. 命令行测试:
curl --no-buffer -H 'Connection: Upgrade' -H 'Upgrade: websocket' -v -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: websocket'  http://127.0.0.1:8081 * About to connect() to 127.0.0.1 port 8081 (#0)
*   Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 8081 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.14.0.0 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 127.0.0.1:8081
> Accept: */*
> Connection: Upgrade
> Upgrade: websocket
> Sec-WebSocket-Version: 13
> Sec-WebSocket-Key: websocket
> 
< HTTP/1.1 101 Switching Protocols
< Upgrade: websocket
< Sec-WebSocket-Version: 13
< Connection: Upgrade
< Sec-WebSocket-Accept: qVby4apnn2tTYtB1nPPVYUn68gY=
  • original 2019-01-13

    多谢回复,找到问题了 上面没有握手成功的原因是返回http头的时候用的单引号, 而我系统是linux,导致没有被解析成换行,所以用PHP_EOL代替\r\n或者双引号代替单引号都可以解决

  • blogdaren 2019-01-13

    @5282: 不客气,是的,我在你代码基础上调试时有发现了单引号的问题。

年代过于久远,无法发表回答
🔝