在TCP打孔中没有来自客户端的确认

时间:2013-12-12 08:56:14

标签: c# tcp hole-punching

我在C#中实现了TCP打孔。我得到的是,客户端正在向对方发送SYN消息,但它们被丢弃在相对的路由器上。场景是这样的: 客户端:--------路由器:甲-------- --------服务器路由器:乙--------客户:乙

如果客户端:A将SYN数据包发送到Client:B,它将被丢弃在Router:B,这是明显的NAT行为。但是,根据打孔场景,现在如果客户端:B向客户端发送SYN:A,它应该通过路由器上的NAT:A。在我的情况下,路由器:A也会丢弃此数据包。在netstat中,它显示B与SYN_SENT的连接,几秒后,我收到一条消息,如“客户端没有响应。连接失败”

根据我的研究,放弃的原因可能是沉默下降或主动拒绝。如果它是静音丢弃,那么应该打孔,并且B中的SYN应该通过A处的NAT传递。如果它是主动拒绝,路由器:A将从路由器获得通知消息:B关于丢弃和A将关闭这个洞。

问题是我在A处没有收到任何通知消息。(通过路由器日志检查)。 我还尝试了一个已经实现的TCP漏洞pucnhing示例 https://github.com/jasonpang/tcp-holepunching

但我得到了类似的结果。帮我找出解决方案。 我也对在路由器上打孔的超时表示怀疑。

命名空间HolePunching {     公共类HolePunchingClient     {         private Socket _clientSocket;

    private Socket _serverSocket;
    private Socket _connectSocket;
    //private Socket _serverSocket;

    private Socket _holePunchedSocket;

    public HolePunchingClient (IPEndPoint localEndPoint)
    {
        /*For the moment, only TCP Hole Punching is supported*/
        _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        _clientSocket.Bind(localEndPoint);

        //_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //_serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        //_serverSocket.Bind(localEndPoint);
    }

    private void ProcessClientRequest (object sender, DoWorkEventArgs eventArgs)
    {
        try
        {
            IPEndPoint iep = (IPEndPoint)eventArgs.Argument;
            _connectSocket.Connect(iep);
            Console.WriteLine("Connected correctly with: " + iep);
            _serverSocket.Close();
            _holePunchedSocket = _connectSocket;
            Console.WriteLine("\n\n\nException check clientRequest\n\n\n");
        }
        catch (Exception e)
        {
            Console.WriteLine("In ProcessClientRequest: " + e.Message);
            return;
        }
    }

    private void ProcessServerRequest (object sender, DoWorkEventArgs eventArgs)
    {
        try
        {
            _serverSocket.Listen(10);
            Socket s = _serverSocket.Accept();
            Console.WriteLine("Received connection from: " + s.RemoteEndPoint);
            _holePunchedSocket = s;
            Console.WriteLine("\n\n\nException check serverRequest\n\n\n");
        }
        catch (Exception e)
        {
            Console.WriteLine("In ProcessServerRequest: " + e.Message);
            return;
        }
    }

    private void ProcessRequest (object sender, DoWorkEventArgs eventArgs)
    {
        while (true)
        {
            byte[] bytes = new byte[2048];
            _clientSocket.Receive(bytes);

            MessageType messageType = (MessageType) bytes[0];
            Console.WriteLine("MessageType received: " + messageType);

            switch (messageType)
            {
                case MessageType.ConnectClient:
                    byte[] byteAddress = new byte[4];
                    byte[] bytePort = new byte[2];
                    Buffer.BlockCopy(bytes, 1, byteAddress, 0, 4);
                    Buffer.BlockCopy(bytes, 5, bytePort, 0, 2);
                    IPEndPoint remoteEndPoint = new IPEndPoint(new IPAddress(byteAddress), BitConverter.ToUInt16(bytePort, 0));
                    Console.WriteLine("HP will be done towards this address: " + remoteEndPoint);

                    _connectSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _connectSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                    _connectSocket.Bind(_clientSocket.LocalEndPoint);

                    _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                    _serverSocket.Bind(_clientSocket.LocalEndPoint);

                    BackgroundWorker bwClient = new BackgroundWorker();
                    bwClient.DoWork += ProcessClientRequest;

                    BackgroundWorker bwServer = new BackgroundWorker();
                    bwServer.DoWork += ProcessServerRequest;

                    bwClient.RunWorkerAsync(remoteEndPoint);
                    bwServer.RunWorkerAsync();

                    break;
            }
        }
    }

    public void Connect (IPEndPoint serverEndPoint)
    {
        _clientSocket.Connect(serverEndPoint);
        _clientSocket.Send(BitConverter.GetBytes((byte)MessageType.Register));

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += ProcessRequest;
        bw.RunWorkerAsync();
    }

    public Socket HolePunch (IPAddress otherAddress)
    {
        byte[] bytes = new byte[5];
        Buffer.BlockCopy(BitConverter.GetBytes((byte)MessageType.RequestClient), 0, bytes, 0, 1);
        Buffer.BlockCopy(otherAddress.GetAddressBytes(), 0, bytes, 1, 4);

        _clientSocket.Send(bytes);

        while (_holePunchedSocket == null)
        {
            System.Threading.Thread.Sleep(1500);
        }

        return _holePunchedSocket;
    }
}

}

这是我从上面的链接中获取的客户端代码。我在连接到客户端B / A时收到异常消息“没有来自其他客户端的响应。连接失败”。

客户端A和B都运行该程序的相同副本。它们中的任何一个都会向服务器发送请求以与其他客户端连接。服务器将IP-Port组合发送给两者。客户端代码将继续向对方发送连接请求(最终会超时)

0 个答案:

没有答案