网络是Linux系统最核心的功能,网络把计算机或局域网连接到一起,本质上是一种进程间通讯的方式,特别是跨系统的进程间通讯,必须通过网络。

网络模型 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

网络中常提起的有七层负载均衡,四层负载均衡,三层设备,二层设备。

这些层来自于国际标准组织定制的 开放式系统互联通讯参考模型(Open systen Interconnection Reference Model), 简称 OSI 网络模型。

OSI 模型把网络互联的框架分为:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

应用层:负责为应用程序提供统一的接口。

表示层:负责把数据转换成兼容接受系统的格式。

会话层:负责维护计算机之间的通信连接。

传输层:负责为数据加上传输表头,形成数据包。

网络层:负责数据的路由和转发。

数据链路层:负责MAC寻址、错误侦测和改错。

物理层:负责在物理网络中传输数据帧。

OSI 模型有些复杂,也没提供一个可实现的方法,所以在Linux中,我们实际上使用的是四层模型,TCP/IP网络模型。

TCP/IP模型,把网络互联的框架分为 应用层、传输层、网络层、网络接口层。

应用层:负责性用户提供一组应用程序,如 HTTP、FTP、DNS等。

传输层:负责端到端的通信,如TCP、UDP等。

网络层:负责网络包的封装,寻址和路由,如IP、ICMP等。

网络接口层:负责网络包在物理网络中的传输,如MAC寻址、错误侦测、通过网卡传输网络帧等。

Linux网络 随笔 第1张Linux网络 随笔 第2张

 Linux网络 随笔 第3张

Linux实际按照TCP/IP模型,实现网络协议栈,平时交流习惯上海市用OSI七层模型描述,七层和四层负载均衡,对应的分别是OSI模型中的应用层和传输层(对应到TCP/IP模型中,实际上是四层和三层)。

Linux网络栈

有了TCP/IP模型后,在网络传输时,数据包就会按照协议栈,对上一层发来的数据进行逐层处理;然后封装上改层的协议头,再发送给下一层。

网络包在每一层的处理逻辑,都取决于各层采用的网络协议,如在应用层,一个提供REST API的应用, 

 可以使用HTTP协议,把需要传输的JSON数据封装到HTTP协议中,然后向下传递给TCP层。

封装就是在原来的负载前后,增加固定格式的元数据,原始的负载数据并不会被修改。

如:通过TCP协议通信的网络包为例 ,如图,应用程序在每一层的封装格式:

Linux网络 随笔 第4张

其中:

  • 传输层在应用程序数据前面增加了TCP头;

  • 网络层在TCP数据包钱增加了IP头;

  • 网络接口层在IP数据包前后分别增加了帧头和帧尾。

 

 新增的头部和尾部,按照特定的协议格式填充:

Linux网络 随笔 第5张

 TCP协议:   

TCP是一种面向连接(连接导向)的、可靠的基于字节流的传输层通信协议。TCP将用户数据打包成报文段,它发送后启动一个定时器,另一端收到的数据进行确认、对失序的数据重新排序、丢弃重复数据。
TCP的特点有:

    • TCP是面向连接的运输层协议
    • 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的
    • TCP提供可靠交付的服务
    • TCP提供全双工通信。数据在两个方向上独立的进行传输。因此,连接的每一端必须保持每个方向上的传输数据序号。
    • 面向字节流。面向字节流的含义:虽然应用程序和TCP交互是一次一个数据块,但TCP把应用程序交下来的数据仅仅是一连串的无结构的字节流。

TCP协议三次握手四次挥手:

 Linux网络 随笔 第6张

特别注意

Seq:是发送方当前报文的顺序号码。
ack:是发送方期望对方在下次返回报文中给回的Seq。

建立连接需要三次握手

第一次握手:客户端向服务端发送连接请求包,标志位SYN(同步序号)置为1,顺序号码为X=0。

第二次握手:服务端收到客户端发过来报文,由SYN=1知道客户端要求建立联机,则为这次连接分配资源。并向客户端发送一个SYN和ACK都置为1的TCP报文,设置初始顺序号码Y=0,将确认序号(ack)设置为上一次客户端发送过来的顺序号(Seq)加1,即X+1 = 0+1=1。

第三次握手:客户端收到服务端发来的包后检查确认号码(ack)是否正确,即第一次发送的Seq加1(X+1=1)。以及标志位ACK是否为1。若正确,服务端再次发送确认包,ACK标志位为1,SYN标志位为0。确认号码(ack)=Y+1=0+1=1,发送顺序号码(Seq)为X+1=1。Server收到后确认号码值与ACK=1则连接建立成功,可以传送数据了。

断开连接需要四次挥手

提醒:中断连接端可以是Client端,也可以是Server端。只要将下面两角色互换即可。
第一次挥手:客户端给服务端发送FIN报文,用来关闭客户端到服务端的数据传送。将标志位FIN和ACK置为1,顺序号码为X=1,确认号码为Z=1。意思是说”我Client端没有数据要发给你了,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK过来。”

第二次挥手:服务端收到FIN后,发回一个ACK(标志位ACK=1),确认号码为收到的顺序号码加1,即X=X+1=2。顺序号码为收到的确认号码=Z。意思是说“你的FIN请求我收到了,但是我还没准备好,请继续你等我的消息" 这个时候客户端就进入FIN_WAIT状态,继续等待服务端的FIN报文。

第三次挥手:当服务端确定数据已发送完成,则向客户端发送FIN报文,关闭与客户端的连接。标志位FIN和ACK置为1,顺序号码为Y=1,确认号码为X=2。意思是告诉Client端“好了,我这边数据发完了,准备好关闭连接了。”

第四次挥手:客户端收到服务器发送的FIN之后,发回ACK确认(标志位ACK=1),确认号码为收到的顺序号码加1,即Y+1=2。顺序号码为收到的确认号码X=2。意思是“我Client端知道可以关闭连接了,但是我还是不相信网络,怕 Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。“(在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。)

为什么关闭的时候却是四次挥(握)手?
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

 TCP头部格式:Linux网络 随笔 第7张

1.源端口号,16位,发送方的端口号。

2.目标端口号,16位,发送方的目标端口号。

3.  32为序列号,sequence number,保证网络传输数据的顺序性。

4.   32位确认号,acknowledgment number,用来确认确实有收到相关封包,内容表示期望收到下一个报文的序列号,用来解决丢包的问题。

5.   头部大小,4位,偏移量:最大值为0x0F,即15,

单位为32位(bit),单位也就是4个字节,给出头部占32bit的数目。没有任何选项字段的TCP头部长度为20字节;最多可以有60(15*4)字节的TCP头部。

6.   Reserved  4位 ,预留字段,都为0

7.  TCP标志位

新增的头部和尾部,增加了网络包的大小,但物理链路中并不能传输任意大小的数据包。网络接口配置的最大单元(MTU),规定了最大IP包大小。常用的以太网中,MTU默认值是1500(也是Linux的默认值)。

网络包超过MTU的大小就会在网络层分片,保证分片后的IP包不大于MTU值。MTU越大,需要分包就越少,网络吞吐能力也就越好。

 Linux通用IP网络栈类似于TCP/IP四层结构:

Linux网络 随笔 第8张

  • 最上层应用程序,需要通过系统调用,来跟套接字接口进行交互;
  • 套接字的下面,就是传输层,网络层和网络接口;
  • 最底层,是网卡驱动程序以及物理网卡设备。

 网卡是收发网络包的基本设备,在系统调用过程中,玩那个卡通过内核中网卡驱动程序注册到系统。网络收发过程中,内核通过中断网卡进行交互。

网络包处理非常复杂,在网卡硬中断只处理最核心的网卡读取和发送,协议中那个的大部分逻辑,会放到软中断中处理。

Linux网络收发流程 

Linux支持众多的虚拟网络设备,网络收发会有些差别。

网络包的接收流程 

  • 网络帧到达网卡后,网卡会通过DMA方式,把这个网络包放到收包队列;然后通过硬中断,告诉终端处理程序已经收到网络包。

  • 接着网卡中断处理程序会为网络帧分配内核数据结构(sk_buff),将其拷贝到sk_buff缓冲区中,再通过软中断,通知讷河收到新的网络帧。

  • 接着,内核协议栈从缓冲区取出网络帧,通过网络协议栈,从下到上逐层处理这个网络帧。如:

  • 在链路层检查报文的合法性,找出上层协议的类型(如IPv4或IPv6),再去掉帧头、帧尾,然后交给网络层。

  • 网络层取出IP头,判断网络包下一步走向,如交给上层还是转发。当网络层确认这个包是要送到本机后,就会取出上层协议中的类型,(如 TCP还是UDP),去掉IP头,再交给传输层。

  • 传输层取出TCP或UDP头后,根据 < 源IP、源端口。目的IP、目的端口>四元组作为标识,找出相对应的Socket,并把数据拷贝到Socket的接受缓存中。

最后,应用程序就可以使用Socket,读取到新接受的数据了。

如图接受流程:(粉色箭头代表处理网络包处理路径)

Linux网络 随笔 第9张

网络包的发送流程  (上图的右半部)

首先,应用程序调用Socket API(如,sendmsg)发送网络包。

有与这是一个系统调用,会陷入到内核的套接字层中,套接字层会把数据包放到Socket发送到缓冲区中。

接着,网络协议栈从Socket发送缓冲区中,取出数据包;再按照TCP/IP栈,从上到下逐层处理。如,传输层和网络层,分别为其增加TCP头和IP头,执行路由查找确认吓一跳的IP,并按照MUT大小进行分片。

分片后的网络包,再送到网络接口层,进行物理地址寻址,找到吓一跳的MAC地址,然后添加帧头和帧尾,放到发包队列中。完成后会有软中断通知驱动程序:发包队列中有新的网络帧需要发送。

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄