PHP socket_read()只获取流的第一个字节


PHP socket_read() only gets the first byte of the stream

在linux中使用socket_read()时,我得到一个非常奇怪的行为。

我正在使用socket_read,缓冲区限制为2048。

在我的windows系统上,它得到整个响应,在我的Linux服务器上,它只得到响应的第一个字节。

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!socket_connect($sock, 'my-server.dyndns.org', 8888)) {
   die('no connect');
}
$req = 'request';
socket_write($sock, $req);
if (false !== ($buf = socket_read($sock, 2048)) {
    echo $buf; // This only contains the first byte of the response.
}
socket_close($sock);

如果我再次调用socket_read(),它会获得字符串的其余部分:

// This works: 
while((false !== ($buf = socket_read($sock, 2048)))) {
    echo "Read ".strlen($buf)." bytes from socket_read().'n";
    if ($buf == "") break;
    $b .= $buf;
    sleep(1);
}
/* Output: 
 *
 * Read 1 bytes from socket_read().
 * Read 307 bytes from socket_read().
 * Read 0 bytes from socket_read().
 * Done.
 */ 

如果在调用socket_read()之前等待2秒,我也会得到一个有效的响应:

// This also works:
sleep(2);
if (false !== ($buf = socket_read($sock, 2048)) {
    echo $buf; // all 308 bytes are read correctly.
}

socket_read()不应该等待缓冲区满了,或者等待字符串结束吗?

我做错了什么?

众所周知,linux上的网络堆栈比windows上的要好得多(更快)(这是主观的,我们只能说:它的行为不同)。另一方面,这意味着您的代码也需要处理这些差异。

Sockets不是实时的,而是异步的。因此,如果您向套接字写入一些内容,您不能期望您已经可以读取它。您需要给远程守护进程一些时间来实际响应您的写操作。

只有当远程端确实写了一些东西到你的套接字,并且网络已经传输了该数据,你才能读取它

你需要量化"整个反应"。

如果"整个响应"是指在套接字关闭之前写入套接字的所有数据,那么您需要使用循环获取更多数据。Recv不能保证在一个块中发送所有的数据。

我强烈建议您不要使用古老的socket_函数,而应该使用fsockopen和read。

在php手册中说,如果类型设置为PHP_NORMAL_READ,则读取以'r 'n结束字符串socket_read(资源$socket, int $length [, int $type = PHP_BINARY_READ])

可能在您的情况下必须使用socket_read($sock, 2048,PHP_NORMAL_READ)来指示它必须在'r'n处停止读取

否则,您可以尝试使用正常的fsockopen,并读取…