TCP打孔

我正在尝试使用mingw toolchain来实现使用Windows套接字的TCP打孔function。 我认为这个过程是正确的,但是这个似乎并不需要。 我用这个作为参考。

  1. AB连接到服务器S
  2. S发送到AB的路由器IP +它用于连接到S的端口
  3. SB也是一样的
  4. 开始2个线程:
    • 一个线程尝试用S发送的信息连接到B的路由器
    • 另一个线程正在等待连接到S时连接到路由器的同一个端口上的传入连接
  5. B也是这样

自从我认为我在代码中没有问题:

  • AB确实得到彼此的IP和端口使用
  • 当他们联系服务器时,他们都在监听他们用来连接路由器的端口
  • 他们都连接到正确的IP和端口,但超时(代码错误10060

我错过了什么?

编辑:在进程资源pipe理器的帮助下,我看到一个客户端设法build立到对等的连接。 但同行似乎并没有考虑要build立联系。

这是我用Wireshark捕获的。 为了举例,服务器S和客户端A在同一台PC上。 服务器S侦听redirect到该PC的特定端口( 8060 )。 B仍然尝试连接正确的IP,因为它看到由S发送的A的公共地址是localhost ,因此使用S的公共IP。 (我用占位符replace了公有IP地址)

Wireshark的

编辑2 :我认为混乱是由于传入和传出连接请求数据传输在同一端口的事实。 这似乎弄乱了连接状态,因为我们不知道哪个套接字将从端口获取数据。 如果我引用msdn:

SO_REUSEADDR套接字选项允许套接字强制绑定到另一个套接字使用的端口。 第二个套接字调用setsockopt,将optname参数设置为SO_REUSEADDR ,将optval参数设置为布尔值TRUE然后调用与原始套接字相同的端口上的绑定。 一旦第二个套接字成功绑定,绑定到该端口的所有套接字的行为是不确定的。

但是使用TCP Hole Punching技术来打开同一个端口是需要的!

Solutions Collecting From Web of "TCP打孔"

一开始2个线程:
一个线程尝试使用S发送的信息连接到B的路由器
另一个线程正在等待连接到S时连接到路由器的同一个端口上的传入连接

你不能用两个线程来做这件事,因为这只是一个操作。 每个进行出站连接的TCP连接也在等待传入连接。 您只需调用“connect”,并且您都发送出站SYN进行连接,并等待入站SYN进行连接。

但是,您可能需要关闭与服务器的连接。 当您已经建立了来自同一端口的连接时,您的平台可能不允许您从端口建立TCP连接。 所以就像你开始TCP打孔一样,关闭到服务器的连接。 绑定一个新的TCP套接字到同一个端口,然后调用connect

遍历到NAT路由器的一个简单的解决方案是使您的流量遵循一个协议,您的NAT已经有一个转发算法,如FTP。

  1. 使用Wireshark检查TCP连接请求(3-way Handhsake进程)是否正常。

  2. 确保您的listner线程正在使用select()来解复用描述符。

  3. sockPeerConect(用于连接其他节点的套接字)在listner Thread中是FD_SET()。

  4. 确保你正在检查

      int listner Thread() { while(true) { FD_SET(sockPeerConn); FD_SET(sockserverConn); FD_SET(nConnectedSock ); if (FD_ISSET(sockPeerConect) { /// and calling accept() in side the nConnectedSock = accept( ....); } if (FD_ISSET(sockserverConn) { /// receive data from server recv(sockserverConn ); } if (FD_ISSET(nConnectedSock ) { /// Receive data from Other Peer recv(nConnectedSock ); } } } 

5.确保您同时启动对等连接A到B和B到A.
6.在连接到服务器和对等点之前启动您的侦听器线程,并使用单个侦听器线程来接收服务器和客户端。

不是每个路由器都支持tcp打孔,请看下面详细解释的文章:

跨网络地址转换器的对等通信