Эмуляция accept () для UDP (проблема синхронизации при настройке демультиплексированных сокетов UDP)

Для архитектуры UDP-сервера, которая будет иметь долговременные соединения, одна архитектура должна иметь один сокет, который прослушивает весь входящий UDP-трафик, а затем создавать отдельные сокеты для каждого подключения с помощью connect () для установки удаленного адреса. Мой вопрос в том, можно ли сделать это атомарно аналогично тому, что accept () делает для TCP.

Причина создания отдельного сокета и использования connect () заключается в том, что это упрощает распределение обработки пакетов по нескольким потокам, а также упрощает прямое связывание сокета со структурами данных, которые необходимы для обработки. Логика демультиплексирования в сетевом стеке направляет входящие пакеты в самый конкретный сокет.

Теперь мой вопрос в основном заключается в том, что происходит, когда кто-то хочет эмулировать accept () для UDP следующим образом:

  1. Используйте select () с fd-set, который включает сокет сервера UDP.

  2. Затем прочтите пакет из сокета сервера UDP.

  3. Затем создайте новый сокет UDP, который затем подключается () к удаленному адресу.

  4. Я вызываю select () с помощью набора fd, который включает оба сокета.

  5. Что возвращается?

учитывая, что пакет приходит в ОС где-то между 1 и 3.

Будет ли пакет демультиплексирован в сокет сервера UDP или он будет демультиплексирован в более конкретный сокет, созданный в 3. То есть, в какой момент происходит демультиплексирование? Когда приходит пакет, или это должно происходить «как будто» он прибыл в точку 4?

Последующий вопрос на случай, если вышеперечисленное не сработает: как лучше всего это сделать?


person Community    schedule 30.06.2009    source источник
comment
Вы уверены, что можете даже создать новый сокет UDP, подключенный к другому концу, и по-прежнему поддерживать тот же порт на стороне сервера? Обычно вы создаете UDP-сокет на другом порту на стороне сервера, серверный сокет используется только для первоначального запроса, дальнейшая связь с одноранговым узлом происходит на 2-х совершенно разных портах. Или просто используйте 1 сокет на сервере и не заботьтесь о его подключении, вам просто нужно записать адрес однорангового узла. UPD в любом случае работает без установления соединения.   -  person nos    schedule 30.06.2009


Ответы (3)


Я вижу, что это обсуждение с 2009 года, но, поскольку оно постоянно всплывает, когда я ищу, я подумал, что должен поделиться своим подходом. И чтобы получить обратную связь, и потому, что мне любопытно, как автор вопроса решил проблему.

То, как я выбрал эмуляцию UDP-accept, было комбинацией номера один и два в ответе nik. У меня есть корневой поток, который прослушивает данный сокет. Я решил использовать TCP для простоты, но изменить этот сокет на UDP не очень сложно. Когда клиент хочет «подключиться» к моему серверу с помощью UDP, он сначала подключается к сокету TCP и запрашивает новое соединение.

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

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

person Kristian Evensen    schedule 10.01.2013

Я нашел этот вопрос после того, как задал его себе здесь ...

UDP-сервер и подключенные сокеты

Поскольку connect () доступен для UDP для указания адреса однорангового узла, мне интересно, почему accept () не был доступен для эффективного завершения подключенного сеанса UDP со стороны сервера. Он может даже переместить дейтаграмму (и любые другие от того же клиента), которая запускает accept (), на новый дескриптор.

Это обеспечит лучшую масштабируемость сервера (см. Обоснование SO_REUSEPORT для получения дополнительной информации), а также надежную аутентификацию DTLS.

person user1715587    schedule 12.01.2019

Это не сработает.
У вас есть два простых варианта.

  1. Создайте многопоточную программу, в которой «корневой» поток прослушивает сокет UDP и «отправляет» полученные пакеты в правильный поток в зависимости от источника. Это потому, что вы хотите разделить обработку по источникам.

    • Extend your protocol so the the sources accept an incoming connection on some fixed port and then continue with the protocol communication. In this case you would let the source request on the standard UDP port (of your choice), then your end will respond from a new UDP socket to the sources' UDP port. This way you have initiated a new UDP path from your end backwards to the known UDP port of each source. That way you have different UDP sockets at your end.
person nik    schedule 30.06.2009
comment
Почему это не сработает? См. lxr.linux.no/linux-bk + v2.6.5 / net / ipv4 / udp.c # L222 для примера ОС, которая будет демультиплексировать на самый конкретный сокет. Моя проблема с вашими предлагаемыми решениями заключается в том, что решение 1 может не масштабироваться, а пакеты, сгенерированные решением 2, могут не доходить до клиентов, находящихся за определенными NAT. - person ; 01.07.2009
comment
Хорошо, я понятия не имел, что вы хотите кодировать под слоем сокетов. - person nik; 01.07.2009