当前位置: 首页 > 知识库问答 >
问题:

如何做TCP打孔?

谭彦
2023-03-14

问题在下面。这是我当前的测试代码,它没有成功。

static void Main(string[] args)
{
    if (args.Count() != 3)
    {
        Console.WriteLine("Bad args");
    }
    var ep = new IPEndPoint(IPAddress.Parse(args[0]), int.Parse(args[1]));
    var lp = new IPEndPoint(IPAddress.Any, int.Parse(args[2]));

    var s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    s.Bind(lp);

    var c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    c.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    c.Bind(lp);

    Task.Run(() => { try { c.Connect(ep); } catch { } });
    s.Listen(10);
    var v = s.Accept();
    v.Close();
}

如何做TCP打孔?我正在使用远程服务器进行测试。我正在运行wget local_public_ip:port/test。我已经为端口80设置了路由器,所以它不需要打孔。我的代码有关联。现在我尝试其他端口,但我不知道如何打孔。

我所做的是(C#代码)

var l = new TcpListener(8090);
l.Start();
try { var o = new TcpClient(); o.Connect("myserverip", 123); }
catch(Exception ex) {}
var e = l.AcceptSocket();
Console.WriteLine(e.RemoteEndPoint.AddressFamily);
TcpClient(new System.Net.IPEndPoint(new System.Net.IPAddress(bytearray), port));
The requested address is not valid in its context

如何做TCP打孔?

共有1个答案

秦俊
2023-03-14

我将使用http://www.bford.info/pub/net/p2pnat/index.html中详细介绍的“顺序穿孔技术”。同时连接和套接字重用似乎要简单得多。打孔不一定要同时做任何事情(无论如何,在分布式系统中这是一个毫无意义的概念)。

我已经实现了打孔。我的路由器好像不喜欢。Wireshark显示出的出站打孔SYN是正确的,但远程方无法接通我。我使用tcpview.exe验证所有端口,并禁用所有防火墙。一定是路由器问题。(它是一个奇怪的入侵路由器。)

class HolePunchingTest
{
    IPEndPoint localEndPoint;
    IPEndPoint remoteEndPoint;
    bool useParallelAlgorithm;

    public static void Run()
    {
        var ipHostEntry = Dns.GetHostEntry("REMOTE_HOST");

        new HolePunchingTest()
        {
            localEndPoint = new IPEndPoint(IPAddress.Parse("LOCAL_IP"), 1234),
            remoteEndPoint = new IPEndPoint(ipHostEntry.AddressList.First().Address, 1235),
            useParallelAlgorithm = true,
        }.RunImpl();
    }

    void RunImpl()
    {
        if (useParallelAlgorithm)
        {
            Parallel.Invoke(() =>
            {
                while (true)
                {
                    PunchHole();
                }
            },
            () => RunServer());
        }
        else
        {

            PunchHole();

            RunServer();
        }
    }

    void PunchHole()
    {
        Console.WriteLine("Punching hole...");

        using (var punchSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            EnableReuseAddress(punchSocket);

            punchSocket.Bind(localEndPoint);
            try
            {
                punchSocket.Connect(remoteEndPoint);
                Debug.Assert(false);
            }
            catch (SocketException socketException)
            {
                Console.WriteLine("Punching hole: " + socketException.SocketErrorCode);
                Debug.Assert(socketException.SocketErrorCode == SocketError.TimedOut || socketException.SocketErrorCode == SocketError.ConnectionRefused);
            }
        }

        Console.WriteLine("Hole punch completed.");
    }

    void RunServer()
    {
        using (var listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            EnableReuseAddress(listeningSocket);

            listeningSocket.Bind(localEndPoint);
            listeningSocket.Listen(0);

            while (true)
            {
                var connectionSocket = listeningSocket.Accept();
                Task.Run(() => ProcessConnection(connectionSocket));
            }
        }
    }

    void ProcessConnection(Socket connectionSocket)
    {
        Console.WriteLine("Socket accepted.");

        using (connectionSocket)
        {
            connectionSocket.Shutdown(SocketShutdown.Both);
        }

        Console.WriteLine("Socket shut down.");
    }

    void EnableReuseAddress(Socket socket)
    {
        if (useParallelAlgorithm)
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    }
}

您可以尝试useparallelalgorithory的两个值。两者都应该管用。

此代码用于服务器。它会在本地NAT中打孔。然后,您可以使用允许选择本地端口的任何客户端从远程端进行连接。我使用了curl.exe。显然,Windows上的telnet不支持绑定到端口。显然也不是。

使用TcpView或Process Explorer验证端口在两侧是否正确。您可以使用Wireshark验证数据包。设置类似tcp.port=1234的筛选器。

当您“调用”来打孔时,您可以启用元组(your-ip,your-port,remote-ip,remote-port)进行通信。这意味着所有进一步的通信都必须使用那些值。所有套接字(入站或出站)必须使用这些确切的端口号。如果您不知道:传出连接也可以控制本地端口。这只是不常见。

 类似资料:
  • 我已经尝试TCP打孔一段时间了,论坛似乎对基于TCP的方法和C编程语言没有多大帮助。主要参考文献如下, 我的设置是 客户端A--NAT-A--Internet--NAT-B--Client B。 假设客户机A知道B的公共endpoint和私有endpoint,而B知道A的endpoint(我已经编写了一个服务器'S',用于在对等点之间交换endpoint信息),并且两个NAT都不对称,如果两个客户

  • 我有一个服务器-客户端程序,它使用TCP连接进行通信。多个客户端可以同时连接到服务器。我想在这个系统上实现tcp打孔。 在客户端,它调用公共服务器来查找我的服务器的公共ip端口。然后连接到它。 编辑:我有另一个想法。就是打开一个新的端口,连接到公共服务器。主服务器端口将像往常一样监听传入连接。当客户端想要连接时,公共服务器会通过新的端口通知我的服务器。它将停止主端口侦听传入的连接,相反,它将连接到

  • 如何验证 Email 地址是否有效 一般来说,你不能。有一些看起来合理的方法可以使用,但却没有办法检测地址 是否实际可以投递,如果没有实际尝试投递的话。 使用正则表达式: # Match basically blah@blah.blah if ( $addr =~ /^\S+\@\S+\.\S+$/ ) { print "Looks OK"; } 如果你干真活的话,可能希望看看 CPAN

  • pnpm monorepo 如何做到批量打包?

  • null 如果或都不能通过TCP启动连接,我将如何管理这种情况?(使用UDP?) 如果在这种情况下TCP打孔不起作用,我可以发送UDP包吗?(UDP在传递方面是不可靠的,所以发送多个重复的数据包能保证传递吗?) 我通常知道穿孔是如何工作的,必须将两个客户端的endpoint相互提供给对方,以便它们都可以尝试发起连接。而且我也很了解纳特的 对于TCP漏洞打孔无效的较少见的情况,可以充当代理

  • 本文向大家介绍nginx基于tcp做负载均衡的方法,包括了nginx基于tcp做负载均衡的方法的使用技巧和注意事项,需要的朋友参考一下 配置多台服务器时,经常需要让各个服务器之间的时间保持同步,如果服务器有外网环境,可以直接同外部的时间服务器更新时间,可以采用rdate命令更新时间: rdate -s tick.greyware.com 可以写个脚本放在/etc/cron.hourly中每小时校