2012-11-15 32 views
2

我试图以非阻塞的方式将大量数据(〜250K)写入流中。PHP Stream Write Buffer

抽象掉的复杂性和对象结构,这就是我运行:

$fp = fsockopen('host', 80); 
socket_set_blocking($fp, false); 
fwrite($fp, $string, $length); // Where $string is a 250K string 

但是数据没有全部被写入。假设这是PHP的写入缓冲区,我设置了stream_set_write_buffer($fp, 0),但是这也没有解决问题。

我把我的fwrite分成了4096B的大块 - 看起来客户端发送了3批完整批(4096字节)和〜1500B批。任何和所有连续调用fwrite都会返回写入的0字节。

有没有人有任何想法我可以排队这个数据全部以非阻塞的方式发出?如果我删除socket_set_blocking($fp, false); - 它一切正常。很显然,这是异步运行的问题。

你的想法是什么?套接字扩展会在这里帮助吗?它以不同的方式处理缓冲区

注:我有意写这个套接字传输层,以避免由于各种原因使用卷曲。使用curl_multi()不是一个选项。

+0

你应该使用'socket_select()'来找出套接字是否准备好写入。 –

+0

由于文件限制问题,无法重新编译PHP而无法使用socket_select。 select()系统调用相对较差。 - 这是我唯一的选择吗? –

+0

你是什么意思的文件限制问题?你有多少个插座? –

回答

5

你的问题几乎可以肯定是由于对于非阻塞套接字流的操作可能会因新包到达而中断。因此,你不能指望fwrite是原子。在这种情况下,您需要必须依靠您的fwrite调用的返回值来确切地告诉您有多少字节被写入该通道中的流,并继续写入,直到发送所有数据。

例如...

$dataToWrite = 'my data'; 
$bytesToWrite = strlen($dataToWrite); 
$totalBytesWritten = 0; 

while ($totalBytesWritten < $bytesToWrite) { 
    $bytes = fwrite($mySock, substr($dataToWrite, $totalBytesWritten)); 
    $totalBytesWritten += $bytes; 
} 

显然,这个问题还必须考虑的情况下套接字连接消失的一个强大的处理等

+0

是的,但在第一次fwrite返回部分写入之后,所有后续对fwrite的调用似乎都返回0 - 虽然套接字报告它仍然处于打开状态。 –

+0

@ColinMorelli然后,你应该使用'stream_select',并且只有当它告诉你该流可以接受一个写操作而没有阻塞时才会写。您可能还需要验证套接字*是否仍然活着。您可以使用'is_resource($ stream)&&!feof($ stream)' – rdlowrey

+0

执行此操作。请参阅上面我刚才对我自己的回答的评论 - stream_select不幸在我们的环境中不起作用。另外,我肯定套接字连接可用。 'is_resource($ stream)&&!feof($ stream)'返回true,通过使套接字同步一切都按预期工作。连接没有被丢弃。 –

0

你是否考虑阻止和重试?我假设你需要考虑EAGAIN/EWOULDBLOCK/EINTR状态,否则你最终会阻止自己。