Считывание сокетов в многопоточном приложении возвращает ноль байтов или EINTR (104) - PullRequest
0 голосов
/ 06 апреля 2010

Я некоторое время являюсь c-кодером - ни новичком, ни экспертом. Теперь у меня есть определенное демоническое приложение на C на PPC Linux. Я использую PHP socket_connect в качестве клиента для локального подключения к этому сервису. Сервер использует epoll для мультиплексирования соединений через сокет Unix. Переданная пользователем строка анализируется для определенных символов / слов с помощью strstr () и, если она найдена, порождает 4 присоединяемых потока на разных веб-сайтах одновременно. Я использую socket, connect, write и read, чтобы взаимодействовать с указанными веб-серверами через TCP через их порт 80 в каждом потоке. Все соединения и записи кажутся успешными. Однако чтение на сокеты веб-сервера завершается неудачно: либо (A) все 3 потока кажутся зависшими, и только один поток возвращает -1, а значение errno равно 104. Отвечающий поток занимает около 10 минут - вечность :-(. * Я где-то читал, что 104 (EINTR?), Который в контексте сети предполагает, что ... «соединение было сброшено равноправным узлом», или (B) 0 байтов из 3 потоков, и только 1 из 4 потоков фактически возвращает некоторые данные. Разве сокет не предназначен для чтения / записи потокобезопасным? Я использую поточно-ориентированные (и повторно входящие) функции libc, такие как strtok_r, gethostbyname_r и т. д.

* Я сомневаюсь, что указанные веб-хосты на самом деле сбрасывают соединение, потому что когда я запускаю однопоточный автономный (при прочих равных условиях) все работает идеально, но, конечно, последовательно, а не параллельно.

Есть и вторая проблема (упс), я не могу написать обратно клиенту, который подключается к моему epoll-ed Unix-сокету. Мое приложение-демон будет зависать и загружать процессор> 100% навсегда. Пока ничего не написано для клиентов. Я уверен, что клиент (очень типичное PHP-приложение для сокетов) не закрывал соединение, когда это происходит - ошибки не обнаружены. Есть идеи?

Я не могу понять, что не так, даже с Valgrind, GDB или большим количеством логов. Пожалуйста, помогите, где вы можете.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2010

Получение ECONNRESET через 10 минут звучит как результат тайм-аута вашего соединения. Либо веб-сервер не отправляет данные, либо ваше приложение не получает их.

Чтобы проверить первый, подключите такую ​​программу, как Wireshark, к локальному устройству обратной связи и найдите трафик к используемому порту и от используемого вами порта.

Для более позднего ознакомьтесь с man-страницей epoll (). Они упоминают сценарий, в котором использование событий, инициируемых фронтом, может привести к блокировке, поскольку в буфере все еще есть данные, но новые данные не поступают, поэтому не инициируется новое событие.

0 голосов
/ 06 апреля 2010

Да, чтение / запись потокобезопасны. Но остерегайтесь gethostbyname () и getservbyname (), если вы их используете - они возвращают указатели на статические данные и могут быть не поточно-ориентированными.

errno 104 ECONNREFUSED (не EINTR). Используйте strerror или perror, чтобы получить текстовое сообщение об ошибке (например, «Сброс соединения по пиру») для определенного кода ошибки.

Лучший способ выяснить, что происходит не так, часто делать очень подробное ведение журнала - регистрировать результаты каждой операции, а также такие детали, как IP-адрес / порт, к которому подключаются, количество прочитанных / записанных байтов, идентификатор потока, и так далее. И, конечно же, убедитесь, что ваш код регистрации является поточно-ориентированным: -)

...