【问题标题】:PHP fsockopen client doesn't receive sent dataPHP fsockopen 客户端不接收发送的数据
【发布时间】:2015-11-18 10:34:46
【问题描述】:

我有以下(精简的)代码:

function curl_request_async($url, $params)
{
    foreach ($params as $key => $val) {
        $post_params[] = $key.'='.urlencode($val);
    }
    $post_string = implode('&', $post_params);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port'])?$parts['port']:80,
        $errno, $errstr, 30);
    fwrite($fp, "$type ".$parts['path']." HTTP/1.1\r\n");
    fwrite($fp, "Host: ".$parts['host']."\r\n");
    fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
    fwrite($fp, "Content-Length: ".strlen($post_string)."\r\n");
    fwrite($fp, "Connection: Close\r\n\r\n");

    $bytes_written = fwrite($fp, $post_string);
    var_dump($bytes_written, strlen($post_string));
    // fread($fp, 1);
    // fflush($fp);
    fclose($fp);
}

这段代码的问题是我没有发现请求到达被调用服务器的证据。 var_dump($bytes_written, strlen($post_string));这一行输出了int(493) int(493),所以它应该已经收到了所有的数据,但它没有。

如果我取消注释 fread($fp, 1); 它可以正常工作。这可能是可行的解决方案,但似乎没有意义。必须有更好的方法!

那么我的问题有两个:为什么fread($fp, 1); 解决了我的问题,是否有更好的解决方案?

【问题讨论】:

  • 不要尝试用 PHP 编写自己的 http 客户端,除非您在这两种技术方面都非常胜任并且有几个月的空闲时间来全职工作。仅列举您提供的代码中的错误将超出此处的答案范围。使用卷曲。我知道 PHP 文档很差,但是 C 库文档要好一些,而且可以正常工作。
  • @symcbean 并不难,如果您想支持 httpS 和内容编码协商以及重定向和内容长度以及所有花哨的东西,当然,但如果您只是想要一个简单的http GET 客户端,其实并不难。获取网址\r\nheader1\r\nheader2\r\n\r\nbody ~
  • @hansherik:查看您提供的代码似乎超出了您的能力范围。 TCP套接字不是硬位。您在上面提供的示例比 Lex 的代码更离谱。

标签: php fsockopen php-socket


【解决方案1】:

您的问题可能是您在 PHP 中编写了服务器代码,并且默认情况下您没有 ignore_user_abort=true (请参阅http://php.net/manual/en/misc.configuration.php#ini.ignore-user-abort ),因此当您关闭连接时,您的服务器停止执行您的 php 代码,因此 fread( fp,1) 解决您的问题 - 在 php 开始编写响应之前连接不会关闭

您可以使用此代码创建一个服务器来测试它是否实际连接 -

<?php 
error_reporting(E_ALL);
ini_set('display_errors',1);
$sck=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
if($sck===FALSE){
    die('socket_create failed!');
}
if(!socket_set_block($sck)){
    die("socket_set_block failed!");
}
if(!socket_bind($sck, '0.0.0.0',1337)){
    die("FAILED to bind to port 1337");
}
if(!socket_listen($sck,0)){
    die("socket_listen failed!");
}
$fullFile='';
while((print('listening for connections!'.PHP_EOL)) && false!==($conn=socket_accept($sck))){
    echo "new connection!".PHP_EOL;
    echo "generating crypto iv..";

    while(false!==($buffi=socket_recv($conn,$buff,1024,MSG_WAITALL))){
        if($buffi===0){
            break;//socket_recv's way of
            //saying that the connection closed,
            //apparently. the docs say it should return
            // false, but it doesn't, it just infinitely returns int(0).
            // at least on windows 7 x64 sp1.
        }
        $fullFile.=$buff;
        echo "recieved ".strlen($fullFile)." bytes...".PHP_EOL;
        $buff='';//do i need to clear it? or wiill recv do it for me?
    }
    echo "all bytes recieved (i guess, todo, socket_last_error confirm).";
    echo PHP_EOL;var_dump($fullFule);
    echo "done!".PHP_EOL;
}

die("should never reach this code...");

它将在http://127.0.0.1:1337上创建一个netcat风格的服务器

【讨论】:

    【解决方案2】:

    fread 需要两个参数:资源和要读取的字节长度。 现在你只读取 1 个字节。 fread($fp, 1);

    如果你想读取完整的结果,循环它直到完全读取:

    while(!feof($fp)){
        echo fread($fp, 128);
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-06
      • 1970-01-01
      • 2021-08-24
      • 2016-12-16
      • 1970-01-01
      • 2012-04-03
      • 2021-12-04
      • 2021-06-25
      • 1970-01-01
      相关资源
      最近更新 更多