Я создаю приложение 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 таким образом, что я не могу увидеть? Есть ли лучшие способы сделать это?