TCP-порты в Erlang - PullRequest
       31

TCP-порты в Erlang

3 голосов
/ 11 ноября 2010

Я использую Erlang для кодирования битторрент-клиента. Я застрял на 4 дня с той же проблемой.

Я отправляю рукопожатие всем узлам, каждый из которых имеет свой собственный порт ip:

Я использую gen_tcp: connect для подключения.

Проблема в том, что я не могу получить их ответ. Я провел много исследований и использовал некоторые программы для мониторинга моих входящих / исходящих соединений.

Узлы получают данные и отправляют ответ обратно на порт, который я использовал для отправки им рукопожатия.

Код мудрый: get_tcp: connect выбирает порт и использует этот порт для отправки данных одноранговому узлу. Пир отвечает обратно на этот порт. Однако, как вы знаете в Erlang, вам нужно использовать gen_tcp: listen, чтобы выбрать ответное соединение, и вам нужно указать порт. В моем случае порт, который я должен прослушивать, - это порт, который вернул gen_tcp: connect.

Я могу получить этот номер порта, используя inet: port, но ошибка всегда та же: используется порт. Я понимаю, почему я получаю ошибку, просто потому, что порт, который я пытаюсь прослушать, уже используется gen_tcp: connect. Я пытался закрыть сокет, чтобы освободить порт, но ничего.

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

Любые идеи от всех гуру Эрланга приветствуются. Спасибо,

// Франк.

Ответы [ 2 ]

6 голосов
/ 11 ноября 2010

Что-то здесь не так, позвольте мне подвести итог тому, что вы пытаетесь сделать:

  • Вы используете TCP-соединения, а не UDP

  • TCP-соединение выглядит так:

    Erlang side: IP1:Port1   <---->  Peer side IP2:Port2
    
  • IP2: порт2 - это порт, который вы передаете в gen_tcp: connect, IP1 - это просто IP-адрес интерфейса на вашем локальном компьютере, а порт1, вероятно, является временным портом, выбранным стеком TCP на вашей машине.

  • Если пир ответит на это же соединение, вы просто получите данные как

    {tcp, Socket, Data}
    

    сообщений от имени владельца порта (вероятно, процесс, который вызывает соединение). За исключением случаев, когда вы используете пассивный режим: тогда вы должны вызвать gen_tcp: recv og для получения данных.

  • Если вы вызываете gen_tcp: listen, вместо этого вы пытаетесь открыть другое соединение, возвращаясь назад. Есть протоколы, которые делают такие вещи, например FTP, но вы должны использовать другой номер порта (обычно вызывайте listen, затем получите номер порта и отправьте их по существующему соединению клиенту, который может подключиться к существующему порту). Но почти все более новые протоколы больше этого не делают, так как это грязно и требует межсетевых экранов с отслеживанием состояния. Даже FTP в настоящее время избегает этого. Поэтому я сильно подозреваю, что вы не хотите этого делать.

1 голос
/ 11 ноября 2010

В Bittorrent есть два способа подключения пиров друг к другу:

  • Ваш клиент инициирует соединение с партнером, это gen_tcp:connect. Установленное соединение является двунаправленным, и это единственное соединение - то, что вы используете для всех коммуникаций.

  • Узел подключается обратно к вашему клиенту. Это путь gen_tcp:listen, за которым следует gen_tcp:accept. Снова устанавливается двунаправленное соединение, которое вы затем используете.

Вы видите используемый порт, вероятно, потому что вы пытаетесь создать соединение "поверх" соединения, которое у вас уже есть. Возможно, стоит прочитать немного о TCP-соединениях.

Жизнеспособный путь решения - начать с предположения, что вы подключаетесь только к другим и игнорируете входящие подключения. Запустите тестовый клиент, который принимает входящие соединения, и все будет работать. Затем вы можете добавить входящие соединения в ваш код, когда работает один из способов. Обратите внимание, что рукопожатие аналогично, но есть небольшие отличия. Например, соединитель сначала отправляет info_hash соединителю (так что соединитель может искать инфо-хеш среди потоков, которые он в данный момент обслуживает).

...