计算机网络体系结构
简介
定义
计算机网络层次结构模型和各层协议的集合。
作用
计算机网络及其部件所应该完成功能的精确定义。
OSI 七层参考模型
物理层(Physical,PH)传递信息需要利用一些物理传输媒体,如双绞线、同轴电缆、光纤等。物理层的任务就是为上层提供一个物理的连接,以及该物理连接表现出来的机械、电气、功能和过程特性,实现透明的比特流传输。在这一层,数据还没有组织,仅作为原始的比特流提交给上层——数据链路层。
数据链路层(Data-link,D)数据链路层负责在 2 个相邻的结点之间的链路上实现无差错的数据帧传输。每一帧包括一定的数据和必要的控制信息,在接收方接收到数据出错时要通知发送方重发,直到这一帧无差错地到达接收结点,数据链路层就是把一条有可能出错的实际链路变成让网络层看起来像不会出错的数据链路。实现的主要功能有:帧的同步、差错控制、流量控制、寻址、帧内定界、透明比特组合传输等。
网络层(Network,N)网络中通信的 2 个计算机之间可能要经过许多结点和链路,还可能经过几个通信子网。网络层数据传输的单位是分组(Packet)。网络层的主要任务是为要传输的分组选择一条合适的路径,使发送分组能够正确无误地按照给定的目的地址找到目的主机,交付给目的主机的传输层。
传输层(Transport,T)传输层的主要任务是通过通信子网的特性,最佳地利用网络资源,并以可靠与经济的方式为 2 个端系统的会话层之间建立一条连接通道,以透明地传输报文。传输层向上一层提供一个可靠的端到端的服务,使会话层不知道传输层以下的数据通信的细节。传输层只存在端系统中,传输层以上各层就不再考虑信息传输的问题了。
会话层(Session,S)在会话层以及以上各层中,数据的传输都以报文为单位,会话层不参与具体的传输,它提供包括访问验证和会话管理在内的建立以及维护应用之间的通信机制。如服务器验证用户登录便是由会话层完成的。
表示层(Presentation,P)这一层主要解决用户信息的语法表示问题。它将要交换的数据从适合某一用户的抽象语法,转换为适合 OSI 内部表示使用的传送语法。即提供格式化的表示和转换数据服务。数据的压缩和解压缩、加密和解密等工作都由表示层负责。
应用层(Application,A)这是 OSI 参考模型的最高层。应用层确定进程之间通信的性质以满足用户的需求,以及提供网络与用户软件之间的接口服务。
TCP/IP 参考模型
网络接口层 TCP/IP 模型的最底层是网络接口层,也被称为网络访问层,它包括了可使用 TCP/IP 与物理网络进行通信的协议,且对应着 OSI 的物理层和数据链路层。TCP/IP 标准并没有定义具体的网络接口协议,而是旨在提供灵活性,以适应各种网络类型,如 LAN、MAN 和 WAN。这也说明,TCP/IP 协议可以运行在任何网络上。
网际层是在 Internet 标准中正式定义的第一层。网际层所执行的主要功能是处理来自传输层的分组,将分组形成数据包(IP 数据包),并为该数据包在不同的网络之间进行路径选择,最终将数据包从源主机发送到目的主机。在网际层中,最常用的协议是网际协议 IP,其他一些协议用来协助 IP 的操作。
传输层传输层也被称为主机至主机层,与 OSI 的传输层类似,它主要负责主机到主机之间的端对端可靠通信,该层使用了 2 种协议来支持 2 种数据的传送方法,它们是 TCP 协议和 UDP 协议。
应用层在 TCP/IP 模型中,应用程序接口是最高层,它与 OSI 模型中高 3 层的任务相同,都是用于提供网络服务,如文件传输、远程登录、域名服务和简单网络管理等。
五层网络协议体系结构
应用层
应用层的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程(进程:主机中正在运行的程序)间的通信和交互的规则。对于不同的网络应用需要不同的应用层协议。在互联网中应用层协议很多,如域名系统 DNS,支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议等等。我们把应用层交互的数据单元称为报文。
传输层
传输层的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务。应用进程利用该服务传送应用层报文。“通用的”是指并不针对某一个特定的网络应用,而是多种应用可以使用同一个运输层服务。
由于一台主机可同时运行多个进程,因此运输层有复用和分用的功能。所谓复用就是指多个应用层进程可同时使用下面运输层的服务,分用和复用相反,是运输层把收到的信息分别交付上面应用层中的相应进程。
网络层
在计算机网络中进行通信的两个计算机之间可能会经过很多个数据链路,也可能还要经过很多通信子网。网络层的任务就是选择合适的网间路由和交换结点, 确保数据及时传送。在发送数据时,网络层把运输层产生的报文段或用户数据报封装成分组和包进行传送。在 TCP / IP 体系结构中,由于网络层使用 IP 协议,因此分组也叫 IP 数据报,简称数据报。
数据链路层
数据链路层通常简称为链路层。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要使用专门的链路层的协议。在两个相邻节点之间传送数据时,数据链路层将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息(如:同步信息,地址信息,差错控制等)。
在接收数据时,控制信息使接收端能够知道一个帧从哪个比特开始和到哪个比特结束。这样,数据链路层在收到一个帧后,就可从中提出数据部分,上交给网络层。控制信息还使接收端能够检测到所收到的帧中有无差错。如果发现差错,数据链路层就简单地丢弃这个出了差错的帧,以避免继续在网络中传送下去白白浪费网络资源。如果需要改正数据在链路层传输时出现差错(这就是说,数据链路层不仅要检错,而且还要纠错),那么就要采用可靠性传输协议来纠正出现的差错。这种方法会使链路层的协议复杂些。
物理层
在物理层上所传送的数据单位是比特。物理层的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。使其上面的数据链路层不必考虑网络的具体传输介质是什么。“透明传送比特流”表示经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的。
网络协议
TCP 协议
TCP FLAG
CWR:发送主机设置拥塞窗口减少(CWR)标志,以指示它收到了一个设置了 ECE 标志的 TCP 段,并在拥塞控制机制中作出响应。
ECE:ECN-Echo 具有双重角色,具体取决于 SYN 标志的值。它表明:如果 SYN 标志设置为(1),则 TCP 对等体具有 ECN 能力。如果 SYN 标志为清除(0),则在正常传输期间接收到 IP 报头中具有拥塞经历标志设置(ECN = 11)的分组。这用作 TCP 发送方的网络拥塞(或即将发生的拥塞)的指示。
URG:表示紧急指针字段是重要的。
ACK:表示确认字段是重要的。客户端发送的初始 SYN 数据包之后的所有数据包都应设置此标志。
PSH:推送功能。要求将缓冲的数据推送到接收应用程序。
RST:重置连接。
SYN:同步序列号。只有从每一端发送的第一个数据包应该设置此标志。其他一些标志和字段会根据此标志更改含义,有些仅在设置时有效,有些仅在明确时有效。
FIN:来自发送方的最后一个数据包。
三次握手
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect()
时。将触发三次握手。
第一次握手(SYN=1,seq = x)
客户端发送一个 TCP 的 SYN 标志位置为 1 的包,指明客户端打算连接的服务器的端口,以及初始序号 x,保存在包头的序列号(Sequence Number)字段里。发送完毕后,客户端进入
SYN_SENT
状态。第二次握手(SYN=1,ACK = 1,seq = y,ackNum = x + 1 )
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为 1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加 1,即 x + 1。 发送完毕后,服务器端进入
SYN_RCVD
状态。第三次握手(ACK = 1,ackNum = y + 1)
客户端再次发送确认包(ACK),SYN 标志位为 0,ACK 标志位为 1,并且把服务器发来的确认序号字段 + 1,放在确认字段中发送给对方,并且在数据段放写 ISN 的+1
发送完毕后,客户端进入
ESTABLISHED
状态,当服务器端接收到这个包时,也进入ESTABLISHED
状态,TCP 握手结束。
四次挥手
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake)。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close()
操作即可产生挥手操作。
第一次挥手(FIN=1,seq = x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为 1 的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入
FIN_WAIT_1
状态。第二次挥手(ACK = 1,ackNum = x + 1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入
CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入FIN_WAIT_2
状态,等待服务器端关闭连接。第三次挥手(FIN = 1,seq = y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为 1。
发送完毕后,服务器端进入
LAST_ACK
状态,等待来自客户端的最后一个 ACK。第四次挥手(ACK = 1,ackNum = y + 1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入
TIME_WAIT
状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入
CLOSED
状态。客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入
CLOSED
状态。
TCP 重传
重传数据包是 TCP 最基本的错误恢复特性之一,用来应对数据包的丢失。
数据包丢失可能原因有很多,如:出故障的应用程序、流量负载沉重的路由器或临时性的服务中断。
如何决定是否重传?决定是否重传数据包的主要机制叫做:重传计时器,这个计时器负责维护一个重传超时(RTO--Retransmission timeout)的值。
当使用 TCP 传输一个数据包时,就启动重传计时器,当收到这个数据包的 ACK 应答时,计时器就停止。从发送数据包到接收 ACK 确认之间的时间被称为往返时间(Round-Trip time,RTT)。
当报文发送之后,但接收方尚未发送 TCP ACK 报文,发送方假设源报文丢失并将其重传。重传之后,RTO 值加倍;如果在 2 倍 RTO 值到达之前还是没有收到 ACK 报文,就再次重传。如果仍然没有收到 ACK,那么 RTO 值再次加倍。如此持续下去,每次重传 RTO 都翻倍,直到收到 ACK 报文或发送方达到配置的最大重传次数。
最大重传次数取决于发送操作系统的配置值。默认情况下,Windows 主机默认重传 5 次。大多数 Linux 系统默认最大 15 次。两种操作系统都可配置。
流量控制之滑动窗口
滑动窗口实现了 TCP 流量控制。首先明确滑动窗口的范畴:TCP 是全双工协议,会话的双方都可以同时接收和发送数据。TCP 会话的双方都各自维护一个发送窗口
和一个接收窗口
。各自的接收窗口
大小取决于应用、系统、硬件的限制(TCP 传输速率不能大于应用的数据处理速率)。各自的发送窗口
则要求取决于对端通告的接收窗口
,要求相同。
滑动窗口解决的是流量控制的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致。
窗口的概念
发送方的发送缓存内的数据都可以被分为 4 类:
1.已发送,已收到 ACK
2.已发送,未收到 ACK
3.未发送,但允许发送
4.未发送,但不允许发送
其中类型 2 和 3 都属于发送窗口。
接收方的缓存数据分为 3 类:
1.已接收
2.未接收但准备接收
3.未接收而且不准备接收
其中类型 2 属于接收窗口。
滑动机制
发送窗口只有收到发送窗口内字节的 ACK 确认,才会移动发送窗口的左边界。
接收窗口只有在前面所有的段都确认的情况下才会移动左边界。当在前面还有字节未接收但收到后面字节的情况下,窗口不会移动,并不对后续字节确认。以此确保对端会对这些数据重传。
遵循快速重传、累计确认、选择确认等规则。
发送方发的 window size = 8192;就是接收端最多发送 8192 字节,这个 8192 一般就是发送方接收缓存的大小。
拥塞控制
拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;常用的方法就是:( 1 )慢启动、拥塞避免( 2 )快速重传、快速恢复。
慢启动
ssthresh 的初始值应该设置为任意高的值,比如接收窗口的大小。
拥塞避免
快速重传
快速重传算法规定,发送方只要连续收到三个重复 ack 就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
快速恢复
当连续收到三个重复的 ack 时,此时不会进入慢启动,而是将 ssthresh 减半,cwnd 线性增长。仅当出现超时,才会进入重新进入慢启动阶段(慢开始算法只是在 TCP 连接建立时和网络出现超时时才使用)。
快速重传为何选择三次重复 ACK
主要的考虑是要区分包的丢失是否由于链路故障还是乱序等其他因素引发。两次 duplicated ACK 时很可能是乱序造成的!三次 duplicated ACK 时很可能是丢包造成的!四次 duplicated ACK 更更更可能是丢包造成的!但是这样的响应策略太慢。丢包肯定会造成三次 duplicated ACK!综上是选择收到三个重复确认时窗口减半效果最好,这是实践经验。
TCP 建立连接时为什么是三次握手,两次握手不行吗?
因为 TCP 的传输是双向的,每个方向通道的建立都需要一次 SYN+ACK,所以建立两个方向的通道最多需要两次(SYN+ACK),即四次握手。但是由于第二次和第三次的握手 SYN 和 ACK 可以合并,因此最少可以三次握手。若只进行两次握手,那么显然只能建立一个单方向的通道,即数据只能从客户端发送到服务器。考虑下面的情况:
因为我们不进行第三次握手,所以在 S 对 C 的请求进行回应(第二次握手)后,就会理所当然的认为连接已建立,而如果 C 并没有收到 S 的回应呢?此时,C 仍认为连接未建立,S 会对已建立的连接保存必要的资源,如果大量的这种情况,S 会崩溃。
全连接、半连接队列
半连接队列
作用:TCP 三次握手中存储处于 SYN_RECD 状态的连接;
最大长度:max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog),syncookies = 0 时起效,syncookies = 1 时将被忽略。
全连接队列
作用:TCP 三次握手中存储处于 ESTABLISHED 状态的连接;
最大长度:min(backlog, net.core.somaxconn) , somaxconn 是一个 os 级别的系统参数,默认值 128, backlog 是在 socket 创建的时候传入的,Nginx、Netty、Tomcat 等均暴露了该参数让应用层来调整。
队列使用情况查看:
当连接处于 LISTEN 状态,Send-Q 表示 accept queue 的最大值,Recv-Q 表示 accept queue 中等待被服务器 accept() 的连接数量,当 Recv-Q >= Send-Q 时,说明全连接队列溢出。
当连接处于非 LISTEN 状态时,Send-Q 表示发送缓冲区还没有被对端 ACK 的数据大小(一般来说在服务端上看到的是指服务端向客户端发送心跳包、断开连接之类的数据包没有被对端响应(ACK)),Recv-Q 表示接受缓冲区还没有读取的数据大小。
队列与三次握手的关系
当连接状态变为 SYN_RCVD
时,连接信息存储到 syns queue;当连接状态变为 ESTABLISHED
时,连接信息从 syns queue 移动到 accept queue;当 accept() 函数从 accept queue 获取连接后,连接信息从队列中移除,具体过程如下:
客户端发送 SYN 请求,请求建立连接,客户端连接状态变为 SYN_SENT;
服务端接受到 SYN 请求,连接状态变为 SYN_RCVD,同时将连接信息存放到 syns 队列中,如果存放成功,则回复 SYN+ACK 给客户端;
当客户端接收到 SYN+ACK 后,连接状态变为 ESTABLISHED,发送 ACK 到服务端,此时客户端可以发送数据;
服务端接收到 ACK 后,连接的状态变为 ESTABLISHED,内核将连接信息从 syns 队列移动到 accept 队列;
服务端应用进程通过 accept()函数从 accept 队列中获取已建立好的连接进行读写,此时连接被移除 accept 队列。
半连接队列溢出处理策略
若设置 net.ipv4.tcp_syncookies = 0 ,服务端会直接丢弃当前 SYN 包(Client 端由于多次重发 SYN 包得不到响应而抛出 connection time out 错误);
若设置 net.ipv4.tcp_syncookies = 1 ,那么 SYN 半连接队列就没有逻辑上的最大值了,/proc/sys/net/ipv4/tcp_max_syn_backlog 设置的值会被忽略;
全连接队列溢出处理策略
如果 tcp_abort_on_overflow=1,服务端会直接发送 RST 包,连接被终止并从 syn queue 中删除(Client 端由于多次重发 SYN 包得不到响应而抛出 connection reset by peer 错误);
如果 tcp_abort_on_overflow=0,服务端会丢弃掉 Client 的 ACK 包,连接信息仍保留在 SYN queue 中,同时启动定时器按照重传机制重新发送 SYN + ACK 包到 Client(执行 net.ipv4.tcp_synack_retries 次重传,每次重传间隔时间 double),当重传次数超过设定值时,服务端发送 RST 包,直接中断连接,并从 syn queue 中删除该连接信息;(在重试次数未达到上限前,重试成功客户端 RT 变高,Client 超时则抛出 read timeout 异常;达到重试上限,则 Client 抛出 connection reset by peer 异常)。
队列溢出问题排查
(backlog 过小)服务端 RT 正常,客户端 RT 较高(RT = 网络+排队+服务端 RT),或者客户端抛出 connection reset by peer、read timeout 等异常;
(backlog 过大且服务端瞬时并发很高)服务端 CPU、Load 异常,客户端 RT 较高或者客户端抛出 connection reset by peer、read timeout 等异常。
其他常见问题
如果 Client 走完了 TCP 握手的第三步,在 Client 看来连接已经建立好了,但是 Server 上的对应连接实际没有准备好,这个时候如果 Client 发数据给 Server,Server 会怎么处理呢?
此时 Server 会忽略 Client 发送的数据包,然后 Client 认为数据包丢失进行重传,若重试若干次数后仍没有成功则 Client 认为异常断开连接;
SYNcookie 机制是怎样的,如何避免 syn flood 攻击?
SYNcookie 机制是指将连接信息编码在 ISN(initial sequence number)中返回给客户端,而不需要将半连接保存在队列中,然后利用客户端随后发来的 ACK 带回的 ISN 还原连接信息,以完成连接的建立,从而避免了半连接队列被攻击 SYN 包填满。(因此,当启用 SYNcookie 机制时半连接队列长度可看做无限的)。
netstat 命令和 ss 命令中 Recv-Q 和 Send-Q 含义?
当连接处于 LISTEN 状态时,Send-Q 表示全连接队最大容量,Recv-Q 表示全连接队列实际使用情况;
当连接处于非 LISTEN 状态时,Send-Q 表示发送缓冲区还没有被对端 ACK 的数据大小(一般来说在服务端上看到的是指服务端向客户端发送心跳包、断开连接之类的数据包没有被对端响应(ACK)),Recv-Q 表示接受缓冲区还没有读取的数据大小。
UDP 协议
源端口(Source Port):16(2^16 = 65536 个端口)位的源端口域包含初始化通信的端口号。源端口和 IP 地址的作用是标识报文的返回地址。
目的端口(Destination Port):16 位的目的端口域定义传输的目的端口。这个端口指明报文接收计算机上的应用程序地址接口。
封包长度(Length):UDP 头和数据的总长度。
校验和(Check Sum):和 TCP 和校验和一样,不仅对头数据进行校验,还对包的内容进行校验。
IP 协议
ARP 协议
网络设备有数据要发送给另一台网络设备时,必须要知道对方的网络层地址(即 IP 地址)。IP 地址由网络层来提供,但是仅有 IP 地址是不够的,IP 数据报文必须封装成帧才能通过数据链路层进行发送。数据帧必须要包含目的 MAC 地址,因此发送端还必须获取到目的 MAC 地址。通过目的 IP 地址获取 MAC 地址的过程是由 ARP(Address Resolution Protocol)协议来实现的。
版权声明: 本文为 InfoQ 作者【Geek_541d14】的原创文章。
原文链接:【http://xie.infoq.cn/article/df98674a142f19c829a1703ff】。未经作者许可,禁止转载。
评论