此文目的把网络包端到端传输的流程串起来,篇幅较长,起到抛砖引玉的作用。
为什么需要网络?
就算开发单机游戏也会用到网络,比如充值、上报玩家行为日志、上报BUG等
那么两个设备之间是如何通过网络进行通信呢?设备千千万,需要协商统一的网络协议进行通信;
先了解概念
分层模型:
OSI模型 | TCP/IP模型 | 相关协议 |
应用层 | 应用层 | HTTP/FTP/TELNET/DNS/DHCP |
表示层 | ASCII | |
会话层 | NFS | |
传输层 | 传输层 | TCP/UDP |
网络层 | 网络层 | IP/ICMP |
链路层 | 网络接口层 | ARP/HDLC/PPP/IEEE 802 |
物理层 | RS232/RJ45 |
OSI(Open System Interconnect),即开放式系统互连标准的模型,由ISO定义,一个试图使各种计算机在世界范围内互连为网络的标准框架;OSI参考模型并不是一个标准,而是一个在制定标准时所使用的概念性框架。
应用层:为操作系统或网络应用程序提供访问网络服务的接口;
表示层:对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解;
会话层:管理主机之间的会话进程,即负责建立、管理、终止进程之间的会话;
传输层:是第一个端到端,即主机到主机的层次,负责将上层数据分段并提供端到端的、可靠的或不可靠的传输,处理端到端的差错控制和流量控制问题;
网络层:负责对子网间的数据包进行路由选择;
数据链路层:在不可靠的物理介质上提供可靠的传输,该层的作用包括:物理地址寻址、数据的成帧、数据的检错等
物理层:为上层协议提供了一个传输数据的物理媒体;
这些概念也许都听说过,但是如何理解?
把上面图放大
可以看出,除了两端设备,其它中间设备并没有实现所有层功能
再把上图的分层图放大:
数据与层的关系:
那数据包是如何从个人电脑传送到服务器的呢?
比如我们在个人电脑1访问域名为http://bill.net的服务器,进行一个HTTP请求或一个登录请求
应用层:
数据格式是:[http头部+消息体] 或 [自定义包头+消息体];传输单位:消息或报文(message),数据长度:MSS,工作在操作系统中的用户态;
http协议格式:
我司代号Y协议格式:
魔数16 | 协议版本16 | Msg数据长度16 |
角色UID64 | ||
数据序列号32 | 接口ID32 | 消息类型8 |
数据 |
数据使用protobuf协议封装
数据封装好后,按下来调用socket连接请求
因为填入的是域名,此时对URL进行解析,调用socket的gethostbyname()接口,进行DNS(Domain Name System)解析;
1、如果是浏览器会先查询浏览器是否有缓存对应IP,否则去问操作系统,先检查自己本地的hosts(C:\Windows\System32\drivers\etc或/etc/hosts)文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。
2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。
3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/IP参数中设置(如果没配置则通过DHCP自动获取)的首选DNS服务器(即本地DNS服务器),此服务器收到查询时,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。
4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。
5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.net)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.net域的这台服务器。这台负责net域的服务器收到请求后,如果自己无法解析,它就会找一个管理.net域的下一级DNS服务器地址(http://bill.net)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找http://bill.net域服务器,重复上面的动作,进行查询,直至找到主机。
6、如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把请求转至上上级,以此循环。不管是本地DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。
流程:
获取IP后,数据继续往下走到传输层,此时来到传输层(Transport Layer);
此层的主要作用是负责将上层数据分段并提供端到端的、可靠的或不可靠的传输
数据:[TCP/UDP头部+[http头部+消息体]],传输单位:段(segment)
最大长度:TCP/UDP头部+MSS(Maximum segment size)其中,TCP MSS=1500(MTU)-20(IP包头)-20~60(TCP包头)=1460~1420字节;UDP MSS=1500-20-8(UDP包头)=1472字节
TCP头部:
写过socket编程的同学对这个结构都比较眼熟了
由上图可看出,16位的端口,数值范围为0~65535
源端口的确定由bind()指定,如果没有指定,则由操作系统分配,一般从1024开始
目标端口在connect时指定
端口号是用来连接上层程序的,也就是把传过来的数据通过端口号交给对应的程序(进程)处理
继续往下就是网络层(Internet Layer):此层有 IP 协议(Internet Protocol),负责对子网间的数据包进行路由选择;
数据:IP头部+[TCP头部+[http头部+消息体]];传输单位:包(packet);最大长度:MTU(Maximum Transmission Unit)=1500字节
IPv4头部:
先看IP组成:网络号(网段)+主机号,32位(4字节)
都由子网掩码确定
比如 192.168.1.100/24,表示24个1,二进制则为[11111111-11111111-11111111-00000000],即255.255.255.0
网络号则由子网掩码255.255.255.0 '&' 192.168.1.100 得到192.168.1.0
主机号则为剩下最后8位的数据,即为100
目标IP已经由前面的DNS确定了
源IP地址确定:
如果预先进行了bind,则设置为源IP
否则获取主要IP作为源IP
特殊情况:如果多个网卡怎么办?
查看路由表:
如windows:route PRINT -4
(图中两个0.0.0.0,其中一个未启用,一般只有一个;跃点数是Metric,表示优先级,数据越小优先级越高)
(正常情况下两个网卡设置成同一网段则会导致无法正常连网)
假设请求目标地址为192.168.3.200,则网段为192.168.3.0,匹配成功,则确定源IP地址并填入包头中;
假如请求目标地址为外网IP,则路由表中无法匹配成功,则会自动匹配0.0.0.0这些条目,使用“接口”作为源地址;
如果匹配到两个都是同网段的IP,则使用主要IP作为源IP
比如linux更改源IP:
ip route change default dev eth0 src 192.168.0.22
ip route change to 192.168.0.0/24 dev eth0 src 192.168.0.22
windows:
添加:route add 目标网络 mask 子网掩码 网关 [接口]
删除:route delete +网络目标+网关
修改:route change 网段 mask 子网掩码 [网关]
如:route change 160.12.0.2 mask 255.255.0.0 160.12.0.10
那么路由表是如何生成的?
由上面可知路由表存储着指向特定网络地址的路径,为每个数据包寻找一条最佳的传输路径,方便将该数据有效地传送到目的站点;
生成有两种分类情况:
1.静态路由表
由系统管理员事先设置好固定的路由表;比如通过route add命令设置的情况
2.动态路由表
是根据网络系统的运行情况而自动调整的路由表,根据路由原则协议(Routing Protocol)提供的功能,自动学习和记忆网络运行情况,在需要时自动计算数据传输的最佳路径。
简单点是指动态路由协议(如RIP)自动建立路由表,当你去掉一条连线时,它会自动去掉其路由
常用的路由协议:内部网关路由协议:RIP,OSPF,外部网关路由协议:BGP;不同路由协议有不同的协议报文,也就是通告信息的方式不一样
其次每种路由协议收到其他路由器发送的信息以后最终要计算出路由,计算时使用的方法就叫算法,算法一般有D-V距离矢量算法(RIP,IGRP,EIGRP,BGP协议),L-S链路状态算法(也称SPF最短路径树算法,如ospf,isis协议)
继续往下就是数据链路层(Data Link Layer):在不可靠的物理介质上提供可靠的传输;
数据:报头和起始帧分界符+MAC+[IP头部+[TCP头部+[http头部+消息体]]]+FCS(帧校验序列);传输单位:帧(frame)
先了解概念:
MAC地址(Media Access Control Address):直译为媒体存取控制位址,一般叫物理地址或硬件地址;由网络设备制造商生产时烧录在网卡的EPROM的48位(6字节)地址,具有全球唯一性;如MAC地址:00-16-EA-AE-3C-40,其中前3个字节,16进制数00-16-EA代表网络硬件制造商的编号,它由IEEE(电气与电子工程师协会)分配,后3字节厂家自定义;
MAC的作用是用于相邻设备的物理寻址,把数据通过相邻设备逐步地传送过去,也就是说IP包里的MAC地址是逐步变化的;
查看指令:ipconfig /all 或 route print
MAC源地址确定:直接读取网卡获得
MAC目标地址确定:
先确定目标IP网络号,查询路由表,得到网络目标IP或网关IP,通过获得的IP,作为目标IP填入ARP请求数据中
这时会用到ARP协议(Address Resolution Protocol),ARP仅用于IPv4,IPv6使用ICMPv6;ARP用于发现和确定IP和MAC地址之间的映射关系;
ARP帧格式:
1.先查ARP缓存,如果有IP对应的MAC地址,则直接返回MAC地址;
2.如果缓存没有找到,则使用ARP协议在同网段内广播ARP报文,以太网地址为全1(ff:ff:ff:ff:ff:ff);
3.网段内所有主机收到报文,判断是否为自己的IP,如果不是则丢弃,如果是则打包含有MAC地址的ARP数据进行单独应答;
4.收到回包后,更新ARP缓存,此缓存保持一定的时间,通常是20分钟,可使用arp -a指令查看;
IEEE802局域网标准以太网帧格式数据:
其中:
前导:用于确定一个帧的到达时间,并确定编码位之间的时间量;
起始帧定界符(SDF:Start of Frame Delimiter):固定值0xAB,接收器使用它恢复时钟(因为每个网口不保持精确的时钟同步);
FCS(Frame Check Sequence,帧校验序列):存放循环冗余校验(CRC)。用来检查包传输过程是否有损坏;
广域网标准:
PPP
HDLC
串行链路不同于以太网,因为以太网是一个多路访问的网络,要定位到目的设备需要借助于MAC地址,但串行线路一般的封装协议都是PPP(Point-to-Point Protocol,点到点协议)或HDLC(High-Level Data Link Control,高级数据链路控制协议)封装
这种封装被用于点对点线路,也就是说,一根线缆只连接两台设备,一端发出,另一端肯定可以收到
继续往下就是物理层(Physical Layer)是:作用是在终端设备间传输比特流;
数据:报头和起始帧分界符+MAC+[IP头部+[TCP头部+[http头部+消息体]]]+FCS(帧校验序列);传输单位:比特bit
物理层传输介质:
传输介质及分类
导向性传输介质:电磁波沿着固体媒介传播;介质有:双绞线、同轴电缆、光纤
非导向性传输介质:自由空间,比如空气、水;介质有:无线电、微波、红外线
局域网物理层:
常见标准:
10Base-T、100Base-TX/FX、1000Base-T、1000Base-SX/LX
常见物理层设备:
中继器(repeater):双绞线(RJ-45接口网线)的理论最大传输距离是100M,超过100M信号会衰减,这时候就要用到中继器,它能起到放大信号延长传输距离的作用
集线器(HUB):把数据包广播发送到与集线器相连的所有节点(并不知道数据要发给谁)。相当于一个多端口的中继器,也能起到放大信号的作用,增加传输距离,集线器是属于半双工模式的;平分主机带宽;
广域网物理层:
常见标准:RS-232、V.24、V.35
常见物理层设备:Modem
链路+物理层过程总结:
网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上前导和起始帧定界符,在末尾加上FCS,将数字信息转换为电信号,通过网线发送出去
接着数据通过网口传输到下一级,来到集线器,把数据包广播发送到与集线器相连的所有节点
交换机:里面有一张MAC地址和端口的映射表;根据MAC地址把数据通过指定的网口传送给设备。二层网络设备,基于以太网设计;电信号从网卡到达网线接口,再到交换机里的模块进行接收,交换机将电信号转换为数字信号,然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。交换机的端口本身不具有 MAC 地址,交换机内部维护有一张MAC地址与网线端口映射表,当某个端口接收到一个数据帧时,它会查看这个数据帧的二层头部信息,并进行两个操作;一个操作是将这个数据帧的源 MAC 地址、接收数据帧的端口号作为一个条目保存在自己的 MAC 地址表中,同时重置这个条目的老化计时器时间,如果条目本身存在则只需要更新时间,而静态条目则没有老化时间;第二个操作是,查看目的MAC地址,即通过上面的路由器的MAC地址查找它对应的网线端口,如果此时MAC地址刚好失效,那么交换机会将包发送到除源端口之外的所有端口,最终得到目标端口并缓存下来,最终把数据包转发到路由器;
路由器:三层网络设备,基于 IP 设计;路由器的各个端口都具有 MAC 地址和 IP 地址,能够成为以太网的发送方和接收方;电信号到达网线接口部分,路由器中的模块会将电信号转成数字信号,然后通过包末尾的 FCS 进行错误校验,如果没问题则检查 MAC 头部中的接收方 MAC 地址,看看是不是发给自己的包,如果是就放到接收缓冲区中,否则就丢弃这个包。完成包接收操作之后,路由器就会去掉包开头的 MAC 头部;接着继续拆包,进入IP层操作流程,先通过目标IP到路由表中查找,取得相应的Gateway,如果为空,表示直连,说明目标机找到,直接使用IP包中的目标IP;如果不为空,则表示需要继续路由得到Gateway IP ;通过这两种情况得到的IP地址,再通过 ARP 协议根据IP地址查询 MAC 地址,路由器也有 ARP 缓存,根据查找到的MAC地址设置为接收方MAC,发送方 MAC 地址设置本路由器的MAC地址,重新生成MAC 头部,然后将数字信息转换为电信号,传输到网线上;
Modem:计算机内的信息是由“0”和“1”组成数字信号,而在电话线上传递的却只能是模拟电信号。于是,当两台计算机要通过电话线进行数据传输时,就需要一个设备负责数模的转换;
发送出去的网络包会通过交换机到达下一个路由器或目标机。经过层层转发之后,网络包就到达了最终的目的地。
流程总结:
应用层组装要发给对方的数据
传输层填好端口,用于确定数据是给哪个app进程的
IP层填好IP地址,用于确定数据是传给哪台主机的
链路层填好MAC地址,用于确定下一跳的物理地址
注意:端口和IP地址是不变的,除非NAT之后(路由器NAT后会分配一个端口给主机,根据内网IP和端口对应到新分配的端口,映射表保存在路由器中,并把数据包的IP包头和TCP/UDP包头修改成外网IP和新分配的端口);IP就相当于指引包的最终方向;MAC地址是一层层变的,数据从一个链路到另一个链路的转发,通过目标IP的去向确定下一个链路的设备MAC地址;
其它:
ICMP:(Internet Control Message Protocol)
ICMP 是 TCP/IP 模型中网络层的重要成员,与 IP 协议、ARP 协议、RARP 协议及 IGMP 协议共同构成 TCP/IP 模型中的网络层;即和IP协议处于同一层,但是ICMP协议底层用的是IP协议;IP报头的协议字段代表的是ICMP/TCP/UDP,当协议字段为1时,代表ICMP;
ICMP就是一个“错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况,也能确保连线的准确性。当路由器在处理一个数据包的过程中发生了意外,可以通过ICMP向数据包的源端报告有关事件。
ICMP只能搭配IPv4使用。如果是IPv6的情况下,需要使用ICMPv6
ICMP报头一共8字节:
类型:1字节,说明该报文属于什么类型。
代码:1字节,说明ICMP报文的代码。
检验和:2字节,检验ICMP报文是否有错误
思考问题:
1.个人电脑1发包时,到达IP层的源IP是一个局域网IP,如果服务器回包的时候,他肯定不能通过这个IP传数据回来,那么是如何解决这个问题的呢?
路由器这里涉及到一个技术:
NAT(Network Address Translation)
是将内部私有地址转换成公网地址进行Internet访问。
NAT的好处:
NAT的主要作用,是解决IP地址数量紧缺。当大量的内部主机只能使用少量的合法的外部地址,就可以使用NAT把内部地址转化成外部地址。
NAT还可以防止外部主机攻击内部主机。
家庭电脑用作服务器,主要也是使用了NAT技术的端口映射功能
假设IP地址为192.168.1.100的主机去访问地址为2.2.2.2的服务器,那么具体的通信过程如下:
1、PC机去访问服务器,那么源IP地址为192.168.1.100,端口号为8888,目的IP地址为2.2.2.2,端口号为8989;
2、到达路由器时,它会将数据包 IP ( 192.168.1.100 ) 伪装成 外网公共 IP (假设为1.1.1.1),并自动分配一个没有使用的大于1024的端口如9999,同时路由器会记忆这个联机的封包是由哪一个PC ( 192.168.1.100 ) 端传送来的(通常由IP+端口共同关联);
3、经过路由器NAT后,那么源地址为1.1.1.1,端口号为9999,目的地址为2.2.2.2,端口号为8989,此时将包发向Internet;
4、最终服务器接收到数据包后,此时发送回应数据包,源地址为2.2.2.2,端口号为8989,目的地址为1.1.1.1,端口号为9999;
5、收到 Internet 传送回来的包,由 NAT主机来接收了,这个时候,路由器会去查询原本记录的路由信息,并将目标 IP 由 外网公共IP 改回原来的 192.168.1.100 ;
6、经过路由器NAT后,那么源地址为2.2.2.2,端口号8989,目的地址为192.168.1.100,端口号为8888;
注意:以上是端口地址转换 (PAT) ,是 NAT 的一种特殊情况,因为如果不进行端口转换的话,不同主机相同端口的情况在收包转换时无法区分是发给哪个主机,举个例子,主机A的IP是192.168.1.100,经过NAT后变为1.1.1.1,主机2的IP是192.168.1.200,经过NAT后也变为1.1.1.1,如果不分配端口的话,回包时发给1.1.1.1,则无法区分是回给A还是回给B,就算映射时加上目标IP也不行,因为有可能两台机器访问同一个IP的服务器;因此路由器会自动分配未使用的端口进行关联,也就是说,NAT最多可以关联65536个映射;
上图中,Source Global Port路由器分配最多65535个,所以同时在表中有65535个上限;上图有3台不同的主机IP,相同主机不同的会话或应用都会分配不同的Global端口;
2.为什么接上网线不用任何设置就能正常上网,不需要手动配置IP地址、子网掩码、网关地址、DNS服务器等?
这里涉及到一个技术:
DHCP(Dynamic Host Configuration Protocol,动态主机配置协议):
主要作用是集中地管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息
默认情况下我们接入网线就能上网了,不用手动设置IP之类的参数,因为DHCP是默认打开,就相当于需要自动获取了,一般DHCP服务器地址是路由器
DHCP协议采用客户端/服务器模型,主机地址的动态分配任务由网络主机驱动。当DHCP服务器接收到来自网络主机申请地址的信息时,才会向网络主机发送相关的地址配置等信息,以实现网络主机地址信息的动态配置
有时候我们需要手动分配IP的时候,会设置一下IPv4的配置,填入IP地址、子网掩码、Gateway地址、DNS服务器,此时DHCP就禁用了
一般我们设置端口映射也是在路由器的DHCP里设置
可以在网络和Internet设置->查看硬件和连接属性,里查看网络状态
也可以通过命令查看一下网络信息:ipconfig /all 或 netsh interface ip show config
DHCP服务器为客户端分配IP地址有三种形式:(一般是使用动态分配方式)
自动分配方式(Automatic Allocation),DHCP服务器为主机指定一个永久性的IP地址,一旦DHCP客户端第一次成功从DHCP服务器端租用到IP地址后,就可以永久性的使用该地址。
动态分配方式(Dynamic Allocation),DHCP服务器给主机指定一个具有时间限制的IP地址,时间到期或主机明确表示放弃该地址时,该地址可以被其他主机使用。
手工分配方式(Manual Allocation),客户端的IP地址是由网络管理员指定的,DHCP服务器只是将指定的IP地址告诉客户端主机。
端口:DHCP采用UDP作为传输协议,客户端发送消息到DHCP服务器的的 67号 端口,服务器返回消息给客户端的 68号 端口。
客户端主机开始DHCP过程的第一个报文,是使用广播报文形式,因此不用预先填入DHCP服务器IP就会自动找到
3.为什么根域名服务器只有 13 个呢?
查询根域名服务器的 IP 列表使用的传输协议是 UDP。
当 UDP 包大小超过 MTU 时,就会在 IP 层进行分片,但是只有第一片有 UDP 头部字段(意味着包含有端口号),由于其它分片没有 UDP 头部字段(意味着没有端口号),能否通过防火墙则完全看防火墙的脸色,因为防火墙可能会检查端口号。所以,最好的通信效果就是避免 UDP 包大小超过 MTU 大小,防止在 IP 层发生分片。
Internet 大多数网络接口MTU >= 512,所以RFC1035 规定了 DNS 报文要求被控制在 512 字节之内。
一个查询根域名服务器信息的 DNS 报文要能装下所有的根域名服务节点基本信息,因为 512个字节有限,所以根域名服务节点当然要限制住了。
最终算到是 512 字节大小的 DNS 报文可以装下 14 个根域名服务器节点的信息,不过当时的人觉得留一手,不全用完,所以就规定在了 13 个根域名服务器。
4.美国能让中国从互联网上消失吗?
前面我们知道,根域名服务器共有 13 个。
其中 1 个为主根域名服务器,放置在美国,其余12个均为辅根域名服务器,其中9个放置在美国,欧洲2个,位于英国和瑞典,亚洲1个,位于日本。
可以看到,我们中国并没有一台根域名服务器,而且主根域名在美国,由 ICANN 管理。
如果美国终止 .cn 后缀的解析和申请,会不会导致中国网络瘫痪?不会。
虽说根域名服务器都在国外,但是我们中国已经有很多台「镜像的根域名服务器」了,也就是会向主根域名服务器同步数据到国内的根域名服务器,这意味着根域名服务器的常用记录,我们早就有了备份,相当于我们自己也有了根服务器。
即使美国从主根域名服务器删除了 .cn 记录,也不怕,因为我们已经维护了根域名服务器的镜像,我们自己可以控制镜像的内容,我们可以不同步关于 .cn 记录的删除。
还记得访问根域名服务器是谁吗?就是本地 DNS 服务器,而这个本地 DNS 服务器一般是由国内的网络运营商管理的,只要在我国内对根域名服务器发出的请求,其实都是由这些镜像完成的。对于中国用户来说,对根的请求,一般不会跑到美国去。