我正在尝试使用mingw toolchain来实现使用Windows套接字的TCP打孔function。 我认为这个过程是正确的,但是这个洞似乎并不需要。 我用这个作为参考。
自从我认为我在代码中没有问题:
10060
) 我错过了什么?
编辑:在进程资源pipe理器的帮助下,我看到一个客户端设法build立到对等的连接。 但同行似乎并没有考虑要build立联系。
这是我用Wireshark捕获的。 为了举例,服务器S和客户端A在同一台PC上。 服务器S侦听redirect到该PC的特定端口( 8060
)。 B仍然尝试连接正确的IP,因为它看到由S发送的A的公共地址是localhost
,因此使用S的公共IP。 (我用占位符replace了公有IP地址)
编辑2 :我认为混乱是由于传入和传出连接请求数据传输在同一端口的事实。 这似乎弄乱了连接状态,因为我们不知道哪个套接字将从端口获取数据。 如果我引用msdn:
SO_REUSEADDR
套接字选项允许套接字强制绑定到另一个套接字使用的端口。 第二个套接字调用setsockopt,将optname参数设置为SO_REUSEADDR
,将optval参数设置为布尔值TRUE
然后调用与原始套接字相同的端口上的绑定。 一旦第二个套接字成功绑定,绑定到该端口的所有套接字的行为是不确定的。
但是使用TCP Hole Punching技术来打开同一个端口是需要的!
一开始2个线程:
一个线程尝试使用S发送的信息连接到B的路由器
另一个线程正在等待连接到S时连接到路由器的同一个端口上的传入连接
你不能用两个线程来做这件事,因为这只是一个操作。 每个进行出站连接的TCP连接也在等待传入连接。 您只需调用“connect”,并且您都发送出站SYN进行连接,并等待入站SYN进行连接。
但是,您可能需要关闭与服务器的连接。 当您已经建立了来自同一端口的连接时,您的平台可能不允许您从端口建立TCP连接。 所以就像你开始TCP打孔一样,关闭到服务器的连接。 绑定一个新的TCP套接字到同一个端口,然后调用connect
。
遍历到NAT路由器的一个简单的解决方案是使您的流量遵循一个协议,您的NAT已经有一个转发算法,如FTP。
使用Wireshark检查TCP连接请求(3-way Handhsake进程)是否正常。
确保您的listner线程正在使用select()来解复用描述符。
sockPeerConect(用于连接其他节点的套接字)在listner Thread中是FD_SET()。
确保你正在检查
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打孔,请看下面详细解释的文章:
跨网络地址转换器的对等通信