握手后无法读取客户端发送的数据(套接字php)

时间:2018-02-07 07:13:38

标签: php sockets websocket

<?php
if (!function_exists('http_parse_headers')) {
    function http_parse_headers($raw_headers) {
        $headers = array();
        $key = '';

        foreach(explode("\n", $raw_headers) as $i => $h) {
            $h = explode(':', $h, 2);

            if (isset($h[1])) {
                if (!isset($headers[$h[0]]))
                    $headers[$h[0]] = trim($h[1]);
                elseif (is_array($headers[$h[0]])) {
                    $headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1])));
                }
                else {
                    $headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1])));
                }

                $key = $h[0];
            }
            else { 
                if (substr($h[0], 0, 1) == "\t")
                    $headers[$key] .= "\r\n\t".trim($h[0]);
                elseif (!$key) 
                    $headers[0] = trim($h[0]); 
            }
        }

        return $headers;
    }
}
function go(){
    $starttime = round(microtime(true),2);
    echo "GO() ... <br />\r\n";

    echo "socket_create ...";
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

    if($socket < 0){
        echo "Error: ".socket_strerror(socket_last_error())."<br />\r\n";
        exit();
    } else {
        echo "OK <br />\r\n";
    }


    echo "socket_bind ...";
    $bind = socket_bind($socket, 'artshellorok.tk', 889);//привязываем его к указанным ip и порту
    if($bind < 0){
        echo "Error: ".socket_strerror(socket_last_error())."<br />\r\n";
        exit();
    }else{
        echo "OK <br />\r\n";
    }   

    socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);//разрешаем использовать один порт для нескольких соединений

    echo "Listening socket... ";
    $listen = socket_listen($socket, 5);//слушаем сокет

    if($listen < 0){
        echo "Error: ".socket_strerror(socket_last_error())."<br />\r\n";
        exit();
    }else{
        echo "OK <br />\r\n";
    }

    while(true){ //Бесконечный цикл ожидания подключений
        echo "Waiting... ";
        $accept = @socket_accept($socket); //Зависаем пока не получим ответа
        if($accept === false){
            echo "Error: ".socket_strerror(socket_last_error())."<br />\r\n";
            usleep(100);
        } else {
            echo "OK <br />\r\n";
            echo "Client \"".$accept."\" has connected<br />\r\n";
            $info = http_parse_headers(socket_read($accept, 100000000));
            if(isset($info['Sec-WebSocket-Key'])){
                $key = base64_encode(pack('H*', sha1($info['Sec-WebSocket-Key'] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
                $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
                    "Upgrade: websocket\r\n" .
                    "Connection: Upgrade\r\n" .
                    "Sec-WebSocket-Accept:$key\r\n\r\n";
                socket_write($accept,$upgrade);
                while(socket_read($accept,100000000) != false && socket_read($accept,100000000) != ""){
                    echo socket_read($accept, 100000000);
                }
            }
        }
        if( ( round(microtime(true),2) - $starttime) > 100) { 
            echo "time = ".(round(microtime(true),2) - $starttime); 
            echo "return <br />\r\n"; 
            return $socket;
        }


    }


}

error_reporting(E_ALL); //Выводим все ошибки и предупреждения
set_time_limit(0);      //Время выполнения скрипта не ограничено
ob_implicit_flush();    //Включаем вывод без буферизации 

$socket = go();         //Функция с бесконечным циклом, возвращает $socket по запросу выполненному по прошествии 100 секнуд. 

echo "go() ended<br />\r\n";

if (isset($socket)){
    echo "Closing connection... ";
    @socket_shutdown($socket);
    socket_close($socket);
    echo "OK <br />\r\n";

当客户端连接到套接字(使用http://websocket.org/echo.html和我自己的客户端测试)时握手没问题,但是当我尝试发送数据时。发送的数据显示不正确或甚至不显示(服务器端的数据)。 889 / tcp端口打开。有问题的解决方法服务器端代码通过ssh(putty)运行。

1 个答案:

答案 0 :(得分:1)

您正在从套接字读取三次,并在前两次读取时将读取的数据丢弃。

您应该将其读入变量一次,然后对变量进行比较,而不是函数的直接输出。

$socket_data = socket_read($accept, 100000000);
while($socket_data != false && $socket_data != ""){
    echo $socket_data;
    $socket_data = socket_read($accept, 100000000);
}