于近日, 差不多制作完成了一台对于一部分NAT适用(绝非普适)的打洞机, 现简述工作流程如下
设客户端: C1, C2, 打洞服务器: S。
1. C1 & C2请求连接S, 并且验证连接密码等信息。
S返回相应ID值给C1 & C2, C1 & C2记录。
2. C1 & C2凭ID使用UDP向S发送一个数据报, S记录它们的Endpoint。
以C1主动向S发起向C2的连接请求为例。
3. C1主动向S发起向C2的连接请求, S回复C1一个ack, 并将C2的Endpoint告知C1, 同时将C1的Endpoint告知C2。
4. C1 & C2同时开始接受UDP数据报
C1 & C2同时开始向对方发送数据报。
C1的NAT(可能不止一层)感觉到了C1发给C2(的NAT(可能不止一层))的数据报, 于是给C2(的NAT(可能不止一层))开放了C1向S提交所用的端口(有的NAT好像会变端口)。
C2同理, 于是C1的NAT(可能不止一层)和C2的NAT(可能不止一层)互相开放了端口, 于是打洞成功。
可是某些NAT可能会改变端口, 所以我们需要C1 & C2定时(间隔很小)发送心跳包给对方, 接收到心跳包要返回ack, 顺便记录接收到的Endpoint以便下次发送之用。
UDP也许不稳定, 于是需要自己撰写个简单的比较可靠的基于UDP的传送数据报的协议, 我的实现大概是如下:
1. C1发送数据给C2, 并开始等待ack
2.1. C2收到数据, 校验通过后发给C1一个ack
C1收到ack, 完
2.2. C2没有收到数据或者发送的ack丢了或者网速太慢以至于C1超时, C1回到1步骤。
不用UPnP原因:
1. 好像不支持多重NAT
2. NAT关闭UPnP服务就完蛋了
3. UPnP被妖怪利用就不好了
好像还有个NAT-PMP, 不过好像支持它的路由器不多。
TCP打洞已跪。
Orz已跪。
打洞机已跪。
欢迎一起讨论有关p2p的想法。
orz!
https://github.com/t-k-/tknet
请问楼主心跳包是指的是在客户端间互相发送心跳包吗?还是在客户端向服务端发送?
不太记得了, 不过根据文章描述, 应该是客户端之间互相发送。