два (неправильных) соединения на сокете, который использует listen(1)

Я разрабатываю два приложения на С++, которые используют вызовы сокетов C Linux, сервер и клиент. Сервер прослушивает определенный порт A и получает соединение, используя функцию accept. Я использую int result = ::listen(mySocketFileDescriptor, 1); ограничение максимального количества подключений до 1. Кстати, на сервере я использую параметр SO_REUSEADDR для повторного использования сокета по другим причинам.

Если есть несколько отключений/подключений от клиента, иногда происходит странное поведение: например, клиент успешно подключается к серверу, но затем, когда он отправляет данные, сервер ничего не получает.

В клиентском приложении я подключаюсь к порту A, используя автоматически назначенный порт Linux, назовем его B. Используя netstat, я обнаружил, что клиент подключен к серверу через порт A как из сокета, который использует порт B и от другого, использующего другой порт C. Я отлаживал и видел, что сервер читает из сокета, который использует B, в то время как клиент пишет в сокет, который использует C.

Любая идея о причине такого поведения?

Помимо любой возможной логической проблемы, которая может возникнуть в моем коде, возможно ли заставить сервер всегда отбрасывать старое соединение при установке нового? есть ли какая-либо опция, которую я могу установить на нем?

Заранее спасибо!


person user3770392    schedule 14.09.2015    source источник


Ответы (2)


Вам необходимо более внимательно прочитать listen справочную страницу, поскольку "limit" - это не максимальное количество подключений, которые могут быть сделаны к этому сокету, это ограничение количества подключений, которые могут пытаться подключиться одновременно, прежде чем вы вызовете accept. После того, как вы позвоните accept, можно будет установить другое соединение.

«Стандартное» значение во многих примерах — 5, и тем не менее эти серверы могут обрабатывать сотни подключений.

person Some programmer dude    schedule 14.09.2015
comment
Ты прав, моя вина. Я хотел бы прочитать какую-нибудь другую книгу по TCP/IP, пожалуйста, не стесняйтесь предложить мне ее. В любом случае, я думаю, что это не проблема, так как в сервере, прежде чем делать акцепт, я закрываю и удаляю старый сокет. - person user3770392; 14.09.2015
comment
о книгах, я думал прочитать: W. Richard Stevens, Unix Network Programming, Volume 1: The Sockets Networking API, но кажется довольно старым - person user3770392; 14.09.2015
comment
@ user3770392 это по-прежнему один из лучших учебников в этой области. - person Alnitak; 14.09.2015

Машине на одном конце сетевого соединения непросто распознать, что другой конец отключен. В частности, это очень сложно сделать, если удаленный конец резко разрывает соединение, а не закрывает его должным образом.

Кроме того, ничто не мешает одним и тем же двум машинам устанавливать несколько одновременных соединений. Если вы хотите ограничить это только одним, тогда ваш сервер должен отслеживать, к какому клиенту (клиентам) он в настоящее время подключен, и он должен быть готов обслуживать несколько подключений одновременно, чтобы распознавать, когда новое подключение созданный существующим клиентом. Для этого требуется либо мультиплексирование (например, с использованием select()), либо многопроцессорность. Затем, если он получает новое соединение от клиента, у которого оно уже есть, сервер прекращает обработку старого соединения и закрывает его.

person John Bollinger    schedule 14.09.2015
comment
В моих тестах всегда был один и тот же клиент с одним и тем же IP-адресом. Когда вы говорите об обработке старого соединения, что вы имеете в виду? Я уже каждый раз закрываю старый сокет, но, похоже, это не решает проблему. - person user3770392; 14.09.2015
comment
@user3770392 user3770392, описанный вами тест netstat показывает, что серверная машина имеет два одновременных соединения с клиентом. По крайней мере, на своем конце - может быть, один из них закрыт на стороне клиента, но, очевидно, сервер этого не распознает. Тот, который установлен первым, является старым. Серверная программа может еще не accept()обработать новое соединение, но это совсем другая проблема. Сервер должен accept() установить новое соединение, прежде чем он сможет распознать, что старое соединение следует разорвать. Вот почему вам нужно обрабатывать несколько соединений. - person John Bollinger; 14.09.2015
comment
@user3770392 user3770392, также убедитесь, что вы обрабатываете результаты ошибок от всех ваших вызовов функций. Возможно, система уже сообщила серверной программе об отключении, но сервер это проигнорировал. - person John Bollinger; 14.09.2015
comment
Боллинджер: спасибо за ваши предложения. Дополнительная информация: PID клиента имеет 2 установленных соединения, а сервер - только одно (со старым портом). Я только что попытался принять, а затем уничтожить старый сокет (сохранив его с помощью указателя), но все та же проблема. - person user3770392; 15.09.2015