Подключение пиров в Лидгрен с сервера
Я хотел бы настроить P2P-сервер. Ситуация выглядит следующим образом:
- У меня есть 2+ пира позади NAT'd маршрутизатора (ов).
- У меня есть сервер за маршрутизатором с переадресацией портов на статический IP.
- Задача сервера состоит в том, чтобы зарегистрировать контактную информацию каждого партнера и отправить его любому другому пользователю по запросу.
- Пир может затем запросить у сервера список других и напрямую подключиться к ним.
В настоящее время одноранговые узлы могут подключаться к серверу, регистрировать свои адреса и запрашивать адреса других одноранговых узлов. Моя проблема - знакомство пиров друг с другом.
В настоящее время я получаю внутренние и внешние IP-адреса каждого пира, как это. Он в значительной степени основан на образце главного сервера, который поставляется с Lidgren; однако это просто соединяет пользователей с сеансами клиент / сервер, в то время как мне требуется одноранговая связь.
//client code; getting our internal IP and sending it to the server
NetOutgoingMessage om = server_client.CreateMessage(); //create message on the server's connection
... //header
IPAddress mask;
var endpoint = new IPEndPoint(NetUtility.GetMyAddress(out mask), peer_client.Port); //gets the internal IP address
... //write message data and send to server
Когда сервер получает запрос или когда одноранговый узел регистрируется на сервере, он получает внешний IP-адрес этого однорангового узла из сообщения о подключении. Затем мы получаем доступ к обоим IP-адресам от обоих пиров при обработке запроса:
//server code, handling the peer request message:
...
string key = msg.ReadString();
Output("Requesting peer: " + key);
IPEndPoint requester_internal = msg.ReadIPEndPoint();
IPEndPoint requester_external = msg.SenderEndPoint;
//attempt to find requested user
User u = null;
if (Users.TryGetValue(id, out u))
{
IPEndPoint target_internal = u.IPInternal;
IPEndPoint target_external = u.IPExternal;
...
//send the requested IPs to the sender, and the sender's IPs to the target.
}
Теперь проблема заключается в том, как соединить одноранговые узлы друг с другом, используя эту информацию (или любую другую информацию, необходимую для установления соединения), поскольку другая инфраструктура уже функционирует.
Моей первой попыткой было использование встроенного метода Introduce:
//server code, continuing from the above
//instead of directly sending IPs to users, introduce them ourselves
s_server.Introduce(target_internal, target_external, requester_internal, requester_external, key);
Казалось, что это работает до некоторой степени, но оно подключалось к соединению с сервером на каждом клиенте, а не к одноранговому соединению, и только на отправителе.
Попытка вручную соединиться с отправленными IP-адресами привела к бесконечным "попыткам соединения":
//peer code; handling 'other peer data received' msg
IPEndPoint peer_internal = msg.ReadIPEndPoint();
IPEndPoint peer_external = msg.ReadIPEndPoint();
Output("SERVER: Recieved peer IP. Attempting to connect to:\n" + peer_internal.ToString() + "\n" + peer_external.ToString());
NetOutgoingMessage om = peer_client.CreateMessage();
om.Write((Int32)3); //unique header for debugging purposes
peer_client.Connect(peer_external, om); //tried both internal and external, no dice
И, наконец, пример IP-адресов, которые я вижу, выгружаемых с сервера:
P1 Internal: 169.xxx.xxx.xxx:14243 //local subnet address, using the proper port
P1 External: xxx.xxx.xxx.xxx:62105 //IP address of the system, matching that from any IP testing site, but using a seemingly random port
P2 Internal: 169.xxx.xxx.xxx:14243 //same as above for the second peer
P2 External: xxx.xxx.xxx.xxx:62106
Я полагаю, что проблема заключается в том, что внешний порт однорангового соединения случайно создается где-то вдоль линии, вместо того, чтобы использовать тот, который я указываю при его создании. Как таковой, он не может быть передан заранее. Я был бы рад, если бы пользователям приходилось переадресовывать определенный порт, так как многие P2P-игры работают таким образом.
Другими словами, у меня, кажется, есть все, что мне нужно для правильной работы перфорации NAT, но мне не хватает знаний Лидгрена, чтобы это произошло.
Наконец, вот как я настроил свой peer_client:
//peer code: initialize the connection to any other peers we may connect to later
NetPeerConfiguration pconfig = new NetPeerConfiguration(appidstr_client);
pconfig.Port = 14243; //properly forwarded in router
pconfig.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
pconfig.SetMessageTypeEnabled(NetIncomingMessageType.UnconnectedData, true);
pconfig.AcceptIncomingConnections = true;
peer_client = new NetPeer(pconfig);
peer_client.Start();
1 ответ
Вы включили вводные сообщения, используя "config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);"?
Является ли "14243" опечаткой? В этом примере главный сервер прослушивает 14343, а клиенты - 14242.
"Похоже, это работало до некоторой степени, но оно подключалось к соединению с сервером на каждом клиенте, а не к одноранговому соединению, и только на отправителе". Я не понимаю, что это значит. Если вы используете класс NetPeer, то нет никакого конкретного "соединения с сервером"?
Помните, что IPEndPoint включает номер порта, на случай, если вы храните его где-то в другом месте, возможно, вы захотите установить его в качестве порта, который вы пытаетесь открыть.