3

一度接続すると、ホストのパブリックエンドポイントを送信する、グローバルにアクセス可能なサーバーがあります。2 つのクライアントを使用して接続し、各クライアントで 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 の背後にあり、1 つはホーム ネットワークにあり、もう 1 つはビジネス ネットワークにあります。

Tcp NATトラバーサルの方法については、このドキュメントに従いました。

4

0 に答える 0