查看文章 |
Linux下PHP socket问题
2009-10-09 23:09
因为一些原因,花了一天时间将原来的基于XML-RPC的调用改为直接通过TCP协议完成,不再走HTTP协议(不再使用繁重的XML通讯,采用phpserializer 传输)。服务基于MINA,实现特定的Codec也不困难,但最麻烦的事情在于:在Linux下,读取一个socket中的内容,无论是采用 fread($sock, 4096) 还是 stream_socket_recvfrom($sock, 4096) 在Linux (Windows没问题)下都不能保证正确的读出指定长度(4096byte)。也就是说: function readSocket($socket) { $str = ''; do { $l = stream_socket_recvfrom($socket, 4096); $str .= ''; } while (strlen($socket) === 4096); return $str; } 是无法正确的读出所有的返回内容的,在非Windows 系统下(Linux以及Mac OS), 每次 stream_socket_recvfrom或者fread从socket读出的内容长度是固定的若干种值,在我的测试机上1460以及2000是常出现的情况。当然: function readSocket($socket) { $str = ''; while($l = stream_socket_recvfrom($socket, 4096)) { $str .= $l; } return $str; } 这个函数则更加糟糕,它会导致整个程序挂起,一直处于等待中,直到等到服务器端设置的Idle时限为止。出现这种状况的原因是,当最后一次stream_socket_recvfrom 或者 fread 的时候,如果缓冲区里真的没有内容的话(期望 stream_socket_recvfrom 读出空),这个函数调用会挂起,等待缓冲区填充内容以完成这次读取(也就是说,退出的条件本身不太可能发生,永远到不了头)。 stream_set_blocking($socket, false) 则是更糟糕的。它将直接导致 stream_socket_recvfrom无论缓冲区里有没有内容,都直接返回。基本上,如果采用这种模式的话,发送请求后,立即从 socket 里读取的话,结果都是空。 注意 stream_socket_recvfrom($socket, 4096, STREAM_OOB) 、stream_socket_recvfrom($socket, 4096) 、stream_socket_recvfrom($socket, 4096, STREAM_PEEK) 的区别。 最后,和ProtocolDecoder 一样,在ProtocolEncoder中在编码数据的末尾添加特定的标志(传输的内容中不肯能出现的控制字符,方向键),客户端检测该标志解决此问题。 |
最近读者: