stream_socket_server:客户端浏览器随机中止?

时间:2010-07-16 04:54:33

标签: sockets php

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

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

<?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);
    }

?>

任何将非预期中止数量降至0的解决方案,或任何获得更稳定通信的方法?这可以在我的服务器端解决,还是仅仅是典型的浏览器行为?

2 个答案:

答案 0 :(得分:1)

我测试了你的代码,看来我用fread()读取套接字的效果更好。您还忘记了主循环(while(1)while(true)for(;;)

对代码的修改:

  • stream_socket_accept @stream_socket_accept [有时您会收到警告,因为“关联方没有正确回复”,当然, stream_socket_accept()]
  • 的超时时间
  • 添加了大while(1) { }循环
  • 将套接字的读数从$client_request = stream_get_contents($conn); 更改为while( !preg_match('/\r?\n\r?\n/', $client_request) ) { $client_request .= fread($conn, 1024); }

检查下面的源代码(我使用8080端口,因为我已经在80上监听了Apache):

<?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);
    }
}

答案 1 :(得分:-1)

sleep(1)

之后添加stream_set_blocking