我想建立一个 P2P 配对服务器。情况如下:
- 我在 NAT'd 路由器后面有 2 个以上的对等方。
- 我在静态 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 穿孔正常工作所需的一切,但我缺乏 Lidgren 的知识来实现它。
最后,这是我设置 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();