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