3

我有一个全局可访问的服务器,一旦连接到它,就会发送主机的公共端点。我使用两个客户端连接它,然后在每个客户端上使用一个 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 遍历。

4

0 回答 0