Хобрук: Ваш путь к мастерству в программировании

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

Я использую 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 не хочет работать хорошо. Любые мысли/предложения приветствуются.

09.11.2010

  • Какую библиотеку сокетов вы используете для C++ или вы создали свою собственную (также * nix или Windows)? Кроме того, в чем ошибка? Это просто навсегда блокирует данные sock ›› или происходит что-то большее? Дополнительное примечание; Я давно не использовал PHP-связь с сервером C++, но ваш сервер отправляет завершение в сокет, поэтому он говорит PHP прекратить чтение? Ваш цикл будет непрерывно читаться в PHP, пока сервер не сообщит ему, что сокет завершил отправку информации; заметьте, это не обновление в реальном времени (поскольку оно печатает данные после того, как они были полностью собраны и сохранены в вашем var). 09.11.2010
  • Это может просто отсутствовать в вашем коде, но вы сначала socket_create $sock? 09.11.2010
  • Кроме того, я не вижу этого в вашем коде, но вам нужно будет напечатать $str, когда ваш цикл завершится. 09.11.2010
  • Ой, я случайно пропустил socket_create() из своего кода - обновлено выше. Я должен был уточнить раньше, извините - это на *NIX. Как таковой ошибки нет; сам сервер работает нормально (я могу телнетить и он работает как положено) - это socket_read() PHP, который висит на неопределенный срок. Сервер сокетов - это всего лишь временный сервер, который я собрал, потому что не смог найти подходящего для работы (любые предложения были бы замечательными). 09.11.2010

Ответы:


1

Сокеты в 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");
09.11.2010
  • Действительно, я знал, что они блокируются по умолчанию, но я совершенно забыл либо а) закрыть сокет после того, как ответ был записан, либо б) разорвать цикл. Спасибо за это. Использование символа NULL, похоже, не работает, если я его переключаю (в идеале это не будет новая строка) - если я попытаюсь strpos($str, "\0") после sock << data << "\0", он его не уловит. Есть предположения? 09.11.2010
  • В отличие от C или C++, PHP не помещает нулевые байты в конец строк, поэтому strpos с \0 при тестировании дает логическое значение false. Вы должны указать другой разделитель, использовать тайм-аут (см. Как установить тайм-аут при чтении сокета?) или закрыть сокет со стороны сервера. 09.11.2010
  • Достаточно справедливо - только что понял это, проверив и мою сторону. Спасибо за вашу помощь! 09.11.2010
  • Я думаю, что код можно немного улучшить, выполнив поиск только в $resp: if (strpos($resp, "\n") !== false) break; 08.04.2015

  • 2

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

    09.11.2010

    3

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

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

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

    16.11.2013

    4

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

    09.11.2010
    Новые материалы

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

    Разбор строк запроса в vue.js
    Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

    Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
    «Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..

    Основы принципов S.O.L.I.D, Javascript, Git и NoSQL
    каковы принципы S.O.L.I.D? Принципы SOLID призваны помочь разработчикам создавать надежные, удобные в сопровождении приложения. мы видим пять ключевых принципов. Принципы SOLID были разработаны..

    Как настроить Selenium в проекте Angular
    Угловой | Селен Как настроить Selenium в проекте Angular Держите свое приложение Angular и тесты Selenium в одной рабочей области и запускайте их с помощью Mocha. В этой статье мы..

    Аргументы прогрессивного улучшения почти всегда упускают суть
    В наши дни в кругах веб-разработчиков много болтают о Progressive Enhancement — PE, но на самом деле почти все аргументы с обеих сторон упускают самую фундаментальную причину, по которой PE..

    Введение в Джанго Фреймворк
    Схема «работать умно, а не усердно» В этой и последующих статьях я познакомлю вас с тем, что такое фреймворк Django и как создать свое первое приложение с помощью простых и понятных шагов, а..