Изменить: Извините, случайно отправлен с заголовком для другого вопроса. Исправлена.
Эй, ребята,
Я использую 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 может привести к зависанию сокета (из одного опыта, который я когда-то имел).