推荐一些UDP打洞文章,以及谈谈自己对NAT的理解和自己过去遇到的UDP"坑"

UDP打洞,内网NAT映射问题(直接从我github的MD笔记摘过来了)

UDP通讯,外网向内网发消息,内网无法收到 [问题点数:20分,结帖人pylmcy150]

udp外网无法返回数据到内网 [问题点数:40分,结帖人qianshangding]

请教UDP 打洞是个什么过程,有成功过的请进。 [问题点数:100分,结帖人myth_2002]

求助技术贴:对称型NAT 怎么穿透

udp外网无法返回数据到内网 [问题点数:40分,结帖人qianshangding]

NAT的四种类型

对称NAT穿透的一种新方法

nat 类型及打洞原理

UDP通信在NAT中session保持时间测试

​ 对称NAT进行打洞/穿透比较随缘(家用路由据说一般都不是对称NAT,即是锥形的)。

  • 全锥型(Full Cone)

  • 受限锥型(Restricted Cone) 限制IP

  • 端口受限锥型(Port Restricted Cone) 限制IP和PORT

  • 对称型(Symmetric) 限制IP和PORT,并且不同外网和内部使用NAT的不同PORT

    对称和锥型最大的区别就是是否NAT使用同一个端口了。

​ UDP打洞一般也就P2P的应用场景需要涉及。如果所有交互都是P1->Server->P2的形式,那么用不到UDP打洞。

​ 这里讲讲NAT,如果不想看上面的推荐文章的话,这里简述一下。

​ 首先提一下TCP和UDP。TCP建立连接,所以客户端和服务端交互很丝滑,两方都通过channel就ok了;UDP没有建立连接,所以服务端必须经常获取用户最新的IP和PORT,才能服务端主动发送消息给客户端。

​ 上面简单的说建立连接和没有建立连接,感觉看上去很抽象。其实这里主要是忽略了NAT映射这一个重要概念,才显得抽象。

​ 不管是TCP还是UDP,在client和server交互的过程难免需要经过NAT映射。这里假设client没有自己的公网IP,而server有公网IP(通常我们的家用网络就是没有自己的公网IP,你查的IP是你家办的宽带对应的宽带提供商的公网IP,这个公网IP是很多户人家共用的。而服务器一般都是网上租的,大都有自己的公网IP)。

  1. 首先,你客户端client主动发送UDP—> 服务器Server。这一个过程会经过NAT映射。

    你家宽带IP算是网络提供商网络下的一个私网IP,这个是移动/联通/电信之类的给你的宽带分配的。正常情况下,你私网IP是不能和外网交互的(就好比你自己电脑不联网,能玩单机游戏,但是不能玩网游似的),但是网络提供商提供NAT服务,能够把你和外网某个公网IP:PORT的联系用一个port标识。

    下面IP字段我就随便打打了,不考虑真实性。

    你Client(192.168.1.17:8888)–试图访问外网–> 某公网IP服务器(172.162.12.10:8080)

    上面这个过程本来是不可行的,因为你在一个局域网环境(联通/移动/电信家办宽带),用的是私网IP,但是网络提供商有公网IP,它通过NAT帮你搞定访问问题(这里讲的不是很好,NAT是用来解决IP资源不足的问题,但是我相信懂的人应该懂我意思)

    你Client(192.168.1.17:8888)–网络提供商NAT(假设ip:178.47.16.53 ,port 2045)--> 某公网IP服务器(172.162.12.10:8080)

    上面多了一个NAT过程,用port标识 (192.168.1.17:8888)和(172.162.12.10:8080) 的联系。这个port端口2045是随便写的,具体它给你多少和不同的网络提供商的分配策略有关,可能随机也可能按照某种顺序。

    这里强调NAT的这个port只能唯一标识你的当前这个IP:PORT和外网哪个IP:PORT的联系,这种NAT可能是端口受限锥型(Port Restricted Cone)也可能是对称型(Symmetric)。这个不细说,要知道详细的可以看看上面推荐的关于NAT的解释。

  2. 有了这个NAT映射后,服务器感知到有个client发送数据给自己。注意,这里服务器抓包获取到的IP和PORT不是你Client的,而是网络提供商公网IP和NAT的端口port。

    NAT—>Server(接受到来自178.47.16.53:2045的UDP包,也就是网络提供商IP:NAT端口)。

    服务器并不知道你Client在这个宽带网络下到底是什么私网IP和端口(即192.168.1.17:8888,这个它是不知道的)。

  3. Server–NAT(你家网络提供商NAT)->你Client。

    这个过程,服务器是把数据发给了178.47.16.53:2045,网络提供商IP:NAT端口,那么既然不是发给你的,你怎么会收到UDP数据包??答案就是,NAT通过查找自己的NAT映射表得知port 2045标识的是**(192.168.1.17:8888)和(172.162.12.10:8080) 的联系**,那么通过178.47.16.53:2045的包就会发送到其内网的**(192.168.1.17:8888)也就是你家的私网IP和应用端口**。

最上面推荐的文章对打洞和NAT都解释很清楚了。下面讲讲我自己过去遇到的问题和解决。

​ 以前有次找了个UDP代码,那时候对UDP、TCP那些还不太熟,所以先找网上代码跑跑看能看效果再学习。这时候遇到一个问题,UDPclient和UDPserver都在我本地网络下是能正常交互的,这里代码逻辑就简单的Echo,client发一句话给server,server重新发回来。后面我把UDPserver放到服务器上,结果服务器Linux只用tcpdump抓包能抓到UDP包,程序却收不到UDP包。当时对linux网卡等了解不多,所以没能解决。

​ 最近又回想起来这个事情,于是重跑一遍代码,tcpdump抓包,发现能抓到UCP包,但是程序还是收不到数据。这次我对Linux网卡有过学习了。所以查看ifconfig发现抓包的UDP目的地址是eth0的ip,而服务跑在docker网桥上,所以没能收到UDP包。于是我docker-compose指定了network_mode: host,使得docker容器使用和宿主机相同的网络环境,进而能获取到eth0的包,问题就解决了。

​ 期间顺便给服务端代码加了个HashMap记录client,然后把client的数据发送给所有和服务器交互过的client。我这里4个client每3秒发送UDP包给Server,然后server不管收到谁的UDP包,记录或更新其在HashMap中的IP和port记录,然后把该UDP包的内容发送给HashMap中记录的所有client。(主要最近要做一个群聊的功能,以前是想用UDP,但是那时候出现获取不到数据的问题,后面就用TCP了。最近重新试试,因为对计网\Linux了解多了不少,问题倒是解决挺快的了)

文章语音组织不是很好,欢迎大家指出错误,一起学习进步。

你可能感兴趣的:(计算机网络)