Sockets 流\u套接字\u服务器:客户端浏览器随机中止?

Sockets 流\u套接字\u服务器:客户端浏览器随机中止?,sockets,php,Sockets,Php,下面是一个实验性的http服务器应用程序的部分代码,我是从PHP CLI脚本从头开始构建的(为什么?因为我手头有太多的时间)。下面的示例与PHP关于此函数的手册页面更为匹配。我遇到的问题是,当通过浏览器(到目前为止测试的两个独立系统的Firefox或IE8)连接到此服务器应用程序时,浏览器会向服务器发送一个空的请求负载,并且大约每加载6个页面中的1个页面就中止一次 服务器控制台每次都显示“已连接[客户端信息]”。但是,大约六分之一的连接将导致“客户端请求为空”错误。没有给出任何错误,告诉标头/正

下面是一个实验性的http服务器应用程序的部分代码,我是从PHP CLI脚本从头开始构建的(为什么?因为我手头有太多的时间)。下面的示例与PHP关于此函数的手册页面更为匹配。我遇到的问题是,当通过浏览器(到目前为止测试的两个独立系统的Firefox或IE8)连接到此服务器应用程序时,浏览器会向服务器发送一个空的请求负载,并且大约每加载6个页面中的1个页面就中止一次

服务器控制台每次都显示“已连接[客户端信息]”。但是,大约六分之一的连接将导致“客户端请求为空”错误。没有给出任何错误,告诉标头/正文对套接字的写入响应失败。浏览器通常会继续阅读我给它的内容,但这是不可用的,因为我无法在不知道它是什么的情况下满足客户端的预期请求

<?php $s_socket_uri = 'tcp://localhost:80'; // establish the server on the above socket $s_socket = stream_socket_server($s_socket_uri, $errno, $errstr, 30) OR trigger_error("Failed to create socket: $s_socket_uri, Err($errno) $errstr", E_USER_ERROR); $s_name = stream_socket_get_name($s_socket, false) OR trigger_error("Server established, yet has no name. Fail!", E_USER_ERROR); if (!$s_socket || !$s_name) {return false;} /* Wait for connections, handle one client request at a time Though to not clog up the tubes, maybe a process fork is needed to handle each connection? */ while($conn = stream_socket_accept($s_socket, 60, $peer)) { stream_set_blocking($conn, 0); // Get the client's request headers, and all POSTed values if any echo "Connected with $peer. Request info...\n"; $client_request = stream_get_contents($conn); if (!$client_request) { trigger_error("Client request is empty!"); } echo $client_request."\n\n"; // just for debugging /* <Insert request handling and logging code here> */ // Build headers to send to client $send_headers = "HTTP/1.0 200 OK\n" ."Server: mine\n" ."Content-Type: text/html\n" ."\n"; // Build the page for client view $send_body = "<h1>hello world</h1>"; // Make sure the communication is still active if ((int) fwrite($conn, $send_headers . $send_body) < 1) { trigger_error("Write to socket failed!"); } // Response headers and body sent, time to end this connection stream_socket_shutdown($conn, STREAM_SHUT_WR); } ?>
我测试了你的代码,似乎用
fread()
读取套接字得到了更好的结果。您还忘记了主循环(
while(1)
while(true)
或(;)

对代码的修改:
  • stream\u socket\u accept@stream\u socket\u accept[有时您会收到警告,因为“连接方没有正确响应”,这当然是
    stream\u socket\u accept()的超时时间。
    ]
  • 添加了大
    while(1){}
    循环
  • $client\u request=stream\u get\u contents($conn)更改套接字的读取;
    
    to
    while(!preg_match('/\r?\n\r?\n/',$client_request)){$client_request.=fread($conn,1024);}
检查下面的源代码(我使用8080端口,因为我已经有一个Apache在80上侦听):


Add
sleep(1)
stream\u set\u blocking

之后添加
sleep(1)
很酷。好多了。出于某种原因,我想
stream\u get\u contents()
实际上一直等到收到完整的请求。我猜客户端没有时间发送,在下一次
发送时被推了出去($conn=…
来了并重写了连接。它看起来像是(!preg_match…
如果客户端运行缓慢或故意中止,则循环会暂停和阻止其他连接。我应该在此时停止该进程,还是您知道更好的方法?此外,它似乎适用于GET请求,因为标头部分似乎以[line feed][carries return]结尾但是,在POST请求中没有返回可靠的字符模式,POST数据正好低于此值。我一直在想客户端如何告诉我他们的请求消息何时完成。只是发现主
,而(1)
循环是不必要的。
流\u socket\u accept()
超时可以设置为-1(从不)。这样做可能更好地捕获函数可能抛出的任何其他类型的错误(如果它甚至定义了更多的内部错误案例).总而言之,你让我明白了一个事实,那就是我必须等到客户端完成向我发送完整的请求,而不仅仅是立即处理我收到的任何请求。也许我应该先更深入地阅读http规范,以了解如何处理它们。如果没有其他人响应,我会将此标记为已接受。谢谢!
<?php

$s_socket_uri = 'tcp://localhost:8080';
$s_socket = stream_socket_server($s_socket_uri, $errno, $errstr, 30) OR
    trigger_error("Failed to create socket: $s_socket_uri, Err($errno) $errstr", E_USER_ERROR);
$s_name = stream_socket_get_name($s_socket, false) OR
    trigger_error("Server established, yet has no name.  Fail!", E_USER_ERROR);
if (!$s_socket || !$s_name) {return false;}

while(1)
{
    while($conn = @stream_socket_accept($s_socket, 60, $peer)) 
    {
        stream_set_blocking($conn, 0);
        echo "Connected with $peer.  Request info...\n";
        //    $client_request = stream_get_contents($conn);

        $client_request = "";
        // Read until double \r
        while( !preg_match('/\r?\n\r?\n/', $client_request) )
        {
            $client_request .= fread($conn, 1024);
        }

        if (!$client_request) 
        {
            trigger_error("Client request is empty!");
        }
        echo $client_request."\n\n";
        $headers = "HTTP/1.0 200 OK\n"
            ."Server: mine\n"
            ."Content-Type: text/html\n"
            ."\n";
        $body = "<h1>hello world</h1><br><br>".$client_request;
        if ((int) fwrite($conn, $headers . $body) < 1) {
            trigger_error("Write to socket failed!");
            }
    stream_socket_shutdown($conn, STREAM_SHUT_WR);
    }
}