2010-11-09 105 views
5

编辑:对不起,意外发布与不同问题的标题。固定。无法读取套接字(挂起)

嗨,

我使用PHP连接到本地的C++ socket服务器,以保持一个Web应用程序和几个守护进程之间的状态。我可以将数据发送到套接字服务器,但不能从它接收;它只会阻止socket_read()并无限期地挂起。我是否忘记了一些愚蠢的东西(比如空字符或换行符的不同组合)?在PHP低于:

socket_connect($sock, $addr, $port); 
socket_write($sock, 'Hello world'); 
$str = ''; 
while($resp = socket_read($sock, 1000)) 
    $str .= $resp; 
socket_close($sock); 
die("Server said: {$str}"); 

套接字服务器的相关部分的下方(注意:<<>>符重载):

std::string data; 
sock >> data; 
sock << data << std::endl; 

>>电话Socket::recv(std::string&)>>电话Socket::send(const std::string&)

这从(例如)telnet工作正常,但PHP不想玩的很好。任何想法/建议表示赞赏。

+1

什么套接字库你使用C + +或你创建自己的(* nix或Windows以及)?另外,错误是什么?它是否永远阻塞袜子>>数据或更多的事情发生?额外的笔记;我在一段时间内没有使用C++服务器的PHP通信,但是您的服务器是否向套接字发送了终止消息,以便它告诉PHP停止阅读?您的循环将以PHP持续读取,直到服务器告诉它套接字完成发送信息;它不是一个实时更新的头脑(因为它在完全收集并存储在你的var后打印数据)。 – RageD 2010-11-09 19:38:11

+0

这可能只是从你的代码中丢失,但是你是否先'socket_create' $ sock? – netcoder 2010-11-09 19:41:33

+0

另外,我没有在你的代码中看到这个,但是当你的循环完成时你需要打印$ str。 – RageD 2010-11-09 19:44:50

回答

7

套接字在PHP ,因为在大多数编程语言中,在默认情况下以阻塞模式打开,除非另外使用socket_set_nonblock进行设置。

这意味着除非发生超时/错误或收到数据,socket_read将永远挂在那里。

由于您的终止符似乎是一个新的生产线,尝试:

while($resp = socket_read($sock, 1000)) { 
    $str .= $resp; 
    if (strpos($str, "\n") !== false) break; 
} 
socket_close($sock); 
die("Server said: $str"); 
+0

事实上,我知道它们默认是阻塞的,但我完全忘记了a)在写入响应之后关闭套接字或b)打破循环。感谢那。使用NULL字符似乎不工作,如果我切换它,虽然(理想情况下,它不会是一个新行) - 如果我尝试'strops($ str,“\ 0”)''后'sock << data < <“\ 0”',它没有抓住它。有什么想法吗? – mway 2010-11-09 20:35:21

+0

与C或C++不同,PHP不会在字符串末尾放置空字节,这就是为什么带''0'的strpos'在测试时会产生布尔错误。您必须提供另一个分隔符,请使用超时(请参阅[如何在套接字读取上设置超时?](http://stackoverflow.com/questions/389645/)),或者从服务器端关闭套接字。 – netcoder 2010-11-09 20:43:57

+0

公平 - 只是通过测试我的结果。谢谢你的帮助! – mway 2010-11-09 20:54:39

0

我实际上只是修复了一个与此类似的问题,除了管道(Is php's fopen incompatible with the POSIX open for pipes)。我不知道解决方案在多大程度上是相似的,但也许值得一看?我同意肆虐,你应该坚持读之间的cout和写行只是为了测试,看看C++挂在袜子>>数据线或袜子< <数据线...

1

TCP套接字平时尽量将多个小送话费到一个数据包,以避免发送过多的数据包(Nagle's algorithm)。这可能是send()调用后无法接收任何内容的原因。您必须使用TCP_NODELAY来打开套接字以避免这种情况。

0

您也可以从套接字读取时,试试这个:

if(socket_recv ($socket , $response , 2048 , MSG_PEEK)!==false) 
{ 
    echo "Server said: $response"; 
} 

注:代替MSG_PEEK使用MSG_WAITALL可能导致插座(从一个经验,我曾经有过)挂起。