在linux中使用socket_read()时,我会遇到一种非常奇怪的行为。
我正在使用具有2048缓冲区限制的socket_read。
在我的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()不应该等待缓冲区变满,还是等待字符串结束?
我做错了什么?
答案 0 :(得分:2)
你需要量化“整个反应”。
如果通过“整个响应”,表示在关闭之前写入套接字的所有数据,那么您需要使用循环来获取更多数据。 recv不保证在一个块中发送所有数据。
我强烈建议您不要使用古老的socket_函数,而应使用fsockopen和fread。
答案 1 :(得分:1)
众所周知,linux上的网络堆栈比Windows更好(更快)(这是主观的,我们只是说:它的行为不同)。另一方面,这意味着您的代码也需要处理差异。
套接字不是实时的,而是异步的。因此,如果你向套接字写东西,你不能指望你已经可以阅读它。您需要给远程守护进程一些时间来实际响应您的写入。
只有当远程端确实向您的套接字写了一些内容并且网络已经传输了该数据时,您才能阅读它。
答案 2 :(得分:0)
在php的手册中说如果类型设置为PHP_NORMAL_READ,则读取以\ r \ n结尾 string socket_read(resource $ socket,int $ length [,int $ type = PHP_BINARY_READ])
也许在你的情况下必须是socket_read($ sock,2048,PHP_NORMAL_READ)来表明它必须停止读取\ r \ n
否则你可以尝试使用普通的fsockopen,而不是fread ...它通常在linux上运行良好。