Не удается прочитать из сокета (зависает)

Изменить: Извините, случайно отправлен с заголовком для другого вопроса. Исправлена.

Эй, ребята,

Я использую PHP для подключения к локальному серверу сокетов C ++, чтобы сохранить состояние между веб-приложением и несколькими демонами. Я могу отправлять данные на сервер сокетов, но не получать от него; он просто блокируется на socket_read() и вешает бесконечно. Я забываю что-то немое (как символ NULL или другая комбинация символов новой строки)? 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 не хочет играть хорошо. Любые мысли / предложения приветствуются.

Сокеты в 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"); 

Сокеты TCP обычно пытаются объединить несколько небольших вызовов отправки в один пакет, чтобы избежать отправки слишком большого количества пакетов ( алгоритм Нагле ). Это может быть причиной того, что вы не можете получить ничего после вызова send (). Вам нужно будет открыть сокет с TCP_NODELAY, чтобы этого избежать.

Я на самом деле просто исправил проблему, подобную этой, за исключением труб ( Является php's fopen несовместимым с POSIX открытым для труб ). Я не знаю, в какой степени решение будет похоже, но, может быть, стоит посмотреть? Я согласен с RageD, что вы должны придерживаться cout между строк чтения и записи только для проверки и посмотреть, висит ли C ++ в строке данных sock >> или в строке данных nock << …

Вы также можете попробовать это при чтении из сокета:

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

Примечание. Использование MSG_WAITALL вместо MSG_PEEK может привести к зависанию сокета (из одного опыта, который я когда-то имел).