Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP socket_read()只获取流的第一个字节_Php_Linux_Sockets - Fatal编程技术网

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

PHP socket_read()只获取流的第一个字节,php,linux,sockets,Php,Linux,Sockets,在linux中使用socket_read()时,我有一种非常奇怪的行为 我使用的socket\u 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');

在linux中使用socket_read()时,我有一种非常奇怪的行为

我使用的socket\u 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上的好(快)多(这是主观的,让我们说一下:它的行为不同)。另一方面,这意味着您的代码也需要处理这些差异

套接字不是实时的,而是异步的。因此,如果您将某些内容写入套接字,就不能指望您已经可以在其上读取了。您需要给远程守护进程一些时间来实际响应您的写操作


只有当远程端确实向您的套接字写入了某些内容,并且网络已经传输了这些数据时,您才能读取这些数据。

php手册中说,如果类型设置为php\u NORMAL\u read,则读取以\r\n结束 字符串套接字读取(资源$socket,int$length[,int$type=PHP\u BINARY\u read])

在您的情况下,可能必须是socket\u read($sock,2048,PHP\u NORMAL\u read),以指示它必须在某个时间停止读取\r\n

否则,您可以尝试使用正常的fsockopen,而使用fread。。。它通常在linux上运行良好。

您需要量化“整个响应”

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


我强烈建议您不要使用古老的socket函数,而是使用fsockopen和fread。

您有什么问题?您是否想知道为什么在编写之后需要等待一段时间,直到您可以从套接字读取某些内容?问题是,我不能相信上述两种解决方案。我不能等待任意时间并假设响应是有效的。另一个解决方案有一个类似的问题:如果输出以块的形式发送,我可能会在所有读取完成之前中断读取循环。您可以检查是否有数据,如果没有,请重试(一次又一次)。创建自己的缓冲区,同时解析和处理套接字错误。@hakre我不能确定输出何时完成。当然,这就是你需要等待的原因。这是网络,您需要检查是否有准备好读取的内容。手册建议,当读取指定的缓冲区长度或读取流终止字符时,将返回socket_read。所以当我叫它的时候,我假设我在等待远程执事。不过,它似乎会立即返回缓冲区中当前的内容。使用+
MSG_WAITALL
标志,您可能会有更多的控制权。试试看。不,它不是“已知linux网络堆栈‘更好’或‘更快’”。这只是旋转。可能是这样,但你不能假设是这样。@MarkR:事实上这是主观的,对吧。例如,什么是“更好”?“更快”是什么意思?所以你完全正确,这只是我(和我认识的许多其他人)的看法。但我不会称之为旋转,我不需要做营销。所以,只有你知道。答案是:这只是意味着操作系统之间存在差异,不同的操作系统需要根据不同的平台进行不同的处理。编辑问题以使其更清楚。@hakre MarkR在技术上是正确的。不能假设给定的网络堆栈比另一个更快。也就是说,根据我的经验,PHP拥有大量更适合LAMP环境的工具(可能是因为在PHP的历史上,LAMP或多或少是被假定的)。这是一个自定义服务器应答,它以二进制模式工作(以\0结尾)。所以在我的情况下,这不是一个解决方案。