我有一个全局可访问的服务器,一旦连接到它,就会发送主机的公共端点。我使用两个客户端连接它,然后在每个客户端上使用一个 TcpListener 和 2 个 TcpClient 来尝试相互连接。我可能做错了什么,因为连接总是被拒绝或超时。
这是 2 个客户端的代码。
static void Main(string[] args)
{
Console.Write("Main server hostname [" + defaultServerHost + "]: ");
string serverHost = Console.ReadLine();
TcpClient client = ConnectTcpClient(serverHost.Length > 0 ? serverHost : defaultServerHost, 9009);
TcpListener listener = CreateTcpListener(client.Client.LocalEndPoint as IPEndPoint);
listener.Start();
Task<TcpClient> incommingTraverse = TraverseIncoming(listener);
StreamReader reader = new StreamReader(client.GetStream());
string publicAddress = reader.ReadLine();
Console.WriteLine("Public endpoint: " + publicAddress);
Console.Write("Remote endpoint: ");
string[] remoteEndPointSplit = Console.ReadLine().Split(':');
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Parse(remoteEndPointSplit[0]), int.Parse(remoteEndPointSplit[1]));
TcpClient publicClient = CreateTcpClient(client.Client.LocalEndPoint as IPEndPoint);
bool publicTraverse = TraverseOutgoing(publicClient, remoteEndPoint).Result;
if (publicTraverse)
{
Console.WriteLine("Connected via public connection");
}
else
{
Console.WriteLine("Connection failed");
}
Console.Read();
}
static TcpClient CreateTcpClient(IPEndPoint localEndPoint)
{
TcpClient client = new TcpClient();
client.Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.Client.Bind(localEndPoint);
return client;
}
static TcpListener CreateTcpListener(IPEndPoint localEndPoint)
{
TcpListener listener = new TcpListener(localEndPoint);
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
return listener;
}
static TcpClient ConnectTcpClient(string host, int port)
{
TcpClient client = new TcpClient();
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.Connect(host, port);
return client;
}
static async Task<TcpClient> TraverseIncoming(TcpListener listener)
{
try
{
TcpClient client = await listener.AcceptTcpClientAsync();
Console.WriteLine("Accepted client");
return client;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
static async Task<bool> TraverseOutgoing(TcpClient client, IPEndPoint remoteEndPoint)
{
try
{
await client.ConnectAsync(remoteEndPoint.Address.ToString(), remoteEndPoint.Port);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
两个客户端都在 NAT 之后,一个在家庭网络中,另一个在商业网络中。
我按照这个文档介绍了如何进行 Tcp NAT 遍历。