Использование SO_REUSEPORT для имитации состояния UDP - PullRequest
0 голосов
/ 26 июня 2018

Я создаю приложение p2p, в котором каждый узел может поддерживать соединение с несколькими другими узлами.

Поддерживать соединение легко с TCP. У меня есть сервер, прослушивающий определенный порт на каждом узле. Всякий раз, когда peerA хочет подключиться к peerB, он создает сокет и выполняет вызов подключения к порту прослушивания peerB. Это создает новый сокет, в котором оба партнера могут выполнять все последующие диалоги.

Я хочу смоделировать ту же концепцию рабочего процесса в UDP. Что-то похожее на этот вопрос. Традиционный способ общения с несколькими одноранговыми узлами по протоколу UDP, как я обнаружил, заключается в том, что каждый одноранговый узел прослушивает предварительно определенный порт. Каждый вызов sendTo указывает ip и порт однорангового узла, к которому мы хотим подключиться, и на стороне получателя. Мы используем recvFrom для его обработки в зависимости от того, с какого узла он поступает (например, передача сообщения в поток, который обрабатывает сообщения от этого конкретного равный).

Однако я хотел знать, есть ли способ сделать то же самое без необходимости демультиплексирования на приемнике. Я обнаружил, что флаг SO_REUSEPORT может использоваться для реализации этого http://man7.org/linux/man-pages/man7/socket.7.html

https://lwn.net/Articles/542629/.

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

makeListeningSocket ip port = do
  sock <- socket ip port
  setSocketOption sock ReusePort 1
  bind sock
  return sock

runUDPServer sock = do
  (receivedMessage, peerAddr) <- recvFrom sock 4096
  newSock <- makeListeningSocket "0.0.0.0" 3001
  connect newSock peerAddr
  async (readMessagesFromSock newSock)
  runUDPServer sock

Мне удалось заставить этот подход работать. Однако опция SO_REUSEPORT, похоже, не создается с учетом этого конкретного случая использования. Итак, мой вопрос: есть ли что-то ужасно неправильное в использовании SO_REUSEPORT таким образом, что я не могу увидеть? Есть ли лучшие способы сделать это?

...