by shihang.mai
1. OSI参考模型
网络7层协议就是OSI参考模型实现
网络7层协议
应用层: HTTP、FTP
表示层: 加密、ASCII
会话层: RPC、SQL
传输层: TCP、UDP
网络层: IP
链路层: ATM、ARP
物理层: 802.3
2. TCP/IP参考模型
TCP/IP:传输控制/网际协议
TCP_IP网络
3. TCP3次握手
目的:确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备
其实要理解TCP握手和挥手,从报文头理解最好不过
TCP报文首部.png
- 16位端口号: 源端口号,目标端口号
- 32位序号: 一次TCP通信(从TCP连接建立到断开)过程中某一个传输方向上的字节流的每个字节的编号
- 32位确认号:用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1
- 4位头部长度:表示tcp头部有多少个32bit字(4字节)。因为4位最大能标识15,所以
TCP头部最长是60字节
- 6位标志位:URG(紧急指针是否有效),ACK(表示确认号是否有效),PSH(缓冲区尚未填满),RST(表示要求对方重新建立连接),SYN(建立连接消息标志接),FIN(表示告知对方本端要关闭连接了)
- 16位窗口大小:是TCP流量控制的一个手段。这里说的窗口,指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度
- 16位校验和:由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。这也是TCP可靠传输的一个重要保障
- 16位紧急指针:一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此,确切地说,这个字段是紧急指针相对当前序号的偏移,不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法
开始时,Client为Closed状态,Server端为Listen状态
- 第一次握手
- Client状态变为SYNC_SEND
- 报文头SYN = 1(SYN=1的报文段不能携带数据,但要消耗掉一个序号)
- 32位序列号seq = x
- 第二次握手
- Server状态变为SYN_REVD
- 报文头SYN = 1
- 报文头ACK = 1
- 32位序号seq = y
- 32位确认号=x+1
- 第三次握手
- Client和Server状态变为ESTABLISHED
- 报文头ACK = 1(ACK报文段可以携带数据,不携带数据则不消耗序号)
- 32位确认号= y+1
- 32位序列号seq = x+1
4. 3次握手原因
双方均知道自己的发收能力可行。3次已经足够了,4次显然多余
5. 4次挥手
开始时,双方都是ESTABLISHED状态
TCP4次挥手.png
- 第一次挥手
- Client进入FIN_WAIT_1状态
- 报文头FLN = 1
- 32位序号seq = u
- 第二次挥手
- Server端进入CLOSE_WAIT状态、CLIENT进入FLN_WAIT_2状态
- 报文头ACK = 1
- 32位确认号=u+1
- 32位序号seq = v
- 第三次挥手
- Server端进入LAST_ACK状态
- 报文头FLN = 1
- 报文头ACK = 1
- 32位确认号seq = w
- 32位确认号=u+1
- 第四次挥手
- Client经历TIME_WAIT->CLOSED,Server进入CLOSED状态
- Client从TIME_WAIT->CLOSED,需要等待
2MSL
(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)时间 - 报文头ACK = 1
- 32位序号seq = u+1
- 32位确认号=w+1
6. 4次挥手原因
双方均知道对方已经知道自己要断开链接
7. 客户端从TIME_WAIT->CLOSED需要经历2MSL原因
TIME_WAIT状态存在的意义,下面MSL指最大报文生存时间
- 保证可靠地终止TCP连接:处于TIME_WAIT状态的客户端会向服务端发送ACK,如果此时ACK丢失,目的端会超时重传FIN报文段,目的端收到重传的报文段最少需要2MSL,所以发送端会等待2MSL时间;
- 客户端在发送ACK后,再等待2MSL时间,可以使本次连接所产生的数据段从网络中消失,从而保证关闭连接后不会有还在网络中滞留的数据段去骚扰服务端
此处,假如主动关闭方为Client(可以为Server主动关闭)
- 其中1个MSL,Client发出的最后一次的ACK报文能最终到达Server
- 另外1个MSL,保证Server,当没收到ACK,Server进行FLN重传能够到达Client
8. TCP、UDP、HTTP
- TCP面向连接((如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
- TCP要求安全性,提供可靠的服务,通过TCP连接传送的数据,不丢失、不重复、安全可靠。而UDP尽最大努力交付,即不保证可靠交付。
- TCP是点对点连接的,UDP一对一,一对多,多对多都可以
- TCP传输效率相对较低,而UDP传输效率高,它适用于对高速传输和实时性有较高的通信或广播通信。
- TCP适合用于网页,邮件等;UDP适合用于视频,语音广播等
- TCP面向字节流,UDP面向报文
9. TCP可靠原因
- TCP的连接是基于三次握手,而断开则是四次挥手。确保连接和断开的可靠性
- TCP的可靠性,还体现在有状态;TCP会记录哪些数据发送了,哪些数据被接受了,哪些没有被接受,并且保证数据包按序到达,保证数据传输不出差错
- TCP的可靠性,还体现在可控制。它有报文校验、ACK应答、超时重传(发送方)、失序数据重传(接收方)、丢弃重复数据、流量控制(滑动窗口)和拥塞控制等机制
10. TCP重传机制
- 超时重传
在发送数据报文时,设定一个定时器,每间隔一段时间,没有收到对方的ACK确认应答报文,就会重发该报文
这个时间RTO (Retransmission Timeou)略大于RTT(一个数据包从发出去到回来的时间) - 快速重传
它不以时间驱动,而是以数据驱动。它基于接收端的反馈信息来引发重传 - 带选择确认的重传(SACK)
在快速重传的基础上,接收端返回最近收到的报文段的序列号范围
SACK标记是加在TCP头部选项
字段里面的 - D-SACK
在SACK的基础上做了一些扩展,主要用来告诉发送方,有哪些数据包自己重复接受了
11. 滑动窗口
- 滑动窗口出现的原因:反证法,TCP 发送一个数据,需要收到确认应答,才会发送下一个数据。这样有个缺点,就是效率会比较低
- 窗口是操作系统开辟的一个缓存空间。窗口大小值表示无需等待确认应答,而可以继续发送数据的最大值
- TCP头部中有一个
16位窗口大小
字段,它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度,从而达到流量控制的目的(接受方每次收到数据包,在发送确认报文的时候,同时告诉发送方,自己的缓存区还有多少空余空间)
发送窗口
滑动窗口-发送窗口.png
接收窗口
滑动窗口-接收窗口.png
12. TCP的流量控制
就是基于上面的滑动窗口,每次服务端收到报文后,都告知客户端可用的窗口大小
13. TCP的拥塞控制
-
拥塞窗口是由发送方维护的
,它是用来估算在一段时间内这条链路可以承载和运输的数据的数量。它大小代表着网络的拥塞程度,并且是动态变化的 - TCP的
流量控制
,是作用于接受者的,根据接受者的能力控制发送速度。拥塞控制
,是作用在网络上的,防止过多的数据包注入到网络,避免出现网络负载过大的情况
拥塞控制用以下几种算法去控制
- 慢启动
- 拥塞避免
- 拥塞发生
- 快速恢复
13.1 慢启动
- TCP连接完成,初始化cwnd = 1,表明可以传一个MSS单位大小的数据。
- 每当收到一个ACK,cwnd就加一;
- 每当过了一个RTT,cwnd就增加一倍; 呈指数让升
- 为了防止cwnd增长过大引起网络拥塞,还需设置一个慢启动阀值ssthresh,默认65535字节(slow start threshold)状态变量。当cwnd到达该阀值后,就好像水管被关小了水龙头一样,减少拥塞状态。即当cwnd >ssthresh时,进入了拥塞避免算法
13.2 拥塞避免
- cwnd到达慢启动阀值后
- 每收到一个ACK时,cwnd = cwnd + 1/cwnd
-
当每过一个RTT时,cwnd = cwnd + 1
拥塞避免.jpg
13.3 拥塞发生
当网络拥塞发生丢包时,会发生之前提到的重试机制
- RTO超时重传
- 快速重传
如果发生RTO超时重传,就会使用拥塞发生算法(一夜回到解放前
)
- 慢启动阀值sshthresh = cwnd /2
- cwnd 重置为 1
-
进入新的慢启动过
RTO拥塞发生.jpg
当发生快速重传时,就不需要依赖RTO超时重传
- 拥塞窗口大小 cwnd = cwnd/2
- 慢启动阀值 ssthresh = cwnd
- 进入快速恢复算法
13.4 快速恢复
- cwnd = sshthresh + 3
- 重传重复的那几个ACK(即丢失的那几个数据包),如果再收到重复的 ACK,那么 cwnd = cwnd +1
-
如果收到新数据的 ACK 后, cwnd = sshthresh。因为收到新数据的 ACK,表明恢复过程已经结束,可以再次进入了拥塞避免的算法了
快速恢复.jpg
14. 半链接
- 3次握手前,服务端会从CLOSED->LISTEN状态,同时会在内部创建
半连接队列(SYN队)列和全连接队列(ACCEPT队列)
- 3次握手服务端从LISTEN->SYN_RCVD状态,此时这个连接被推入了SYN队列(半连接队列)
- 3次握手完后后,连接会等待被具体应用取走,被取走前,被推入到ACCEPT队列
14.1 SYN Flood攻击
它一种典型的DoS 攻击,它在短时间内,伪造不存在的IP地址,向服务器大量发起SYN报文。当服务器回复SYN+ACK报文后,不会收到ACK回应报文,导致服务器上建立大量的半连接半连接队列满了,这就无法处理正常的TCP请求。
检测方法:
netstat -n -p TCP | grep SYN_RECV
在服务器上看到大量的半连接状态时,特别是源IP地址是随机的
解决方式:
- syn cookie:在收到SYN包后,服务器根据一定的方法,以数据包的源地址、端口等信息为参数计算出一个cookie值作为自己的SYNACK包的序列号,回复SYN+ACK后,服务器并不立即分配资源进行处理,等收到发送方的ACK包后,重新根据数据包的源地址、端口计算该包中的确认序列号是否正确,如果正确则建立连接,否则丢弃该包
- SYN Proxy防火墙:服务器防火墙会对收到的每一个SYN报文进行代理和回应,并保持半连接。等发送方将ACK包返回后,再重新构造SYN包发到服务器,建立真正的TCP连接
15. 半关闭
当服务端处在CLOSE_WAIT时,就是所谓的半关闭状态。此时客户端可以接收服务器发送的数据,但是客户端已经不能再向服务器发送数据
大量CLOSE_WAIT的危害:如果Server大量连接长期保持在CLOSE_WAIT状态,也就是说分配的文件描述符并没有关闭并归还,可能到最后就没有可分配的文件描述符了,那么就会使一些客户端无法连接
16. Nagle算法和延迟确认
Nagle算法用来解决发送端疯狂发送很小的包问题,为了尽可能发送大块数据。它基本定义:任意时刻,最多只能有一个未被确认的小段(小于MSS的数据块)
规则如下:
- 如果包长度达到MSS,则允许发送;
- 如果该包含有FIN,则允许发送;
- 设置了TCP_NODELAY选项,则允许发送;
- 未设置TCP_CORK选项时,若所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送;
- 上述条件都未满足,但发生了超时(一般为200ms),则立即发送
延迟确认就是指接收方收到数据包后,如果暂时没有数据要发给对端,它可以等一段时再确认。如果这段时间刚好有数据要传给对端,ACK就随着数据传输,而不需要单独发送一次ACK。如果超过时间还没有数据要发送,也发送ACK,避免对端以为丢包。
一般情况下为了性能,这两者是不能一起使用的
17. TCP的粘包和拆包
TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题
为什么会产生粘包和拆包呢?
- 要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包;
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包;
- 要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包;
- 待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。即TCP报文长度-TCP头部长度>MSS。
解决方案
- 发送端将每个数据包封装为固定长度
- 在数据尾部增加特殊字符进行分割
- 将数据分为两部分,一部分是头部,一部分是内容体;其中头部结构大小固定,且有一个字段声明内容体的大小
18. 数据包发送
数据包发送-
当计算机1开机时,它会在链路层发出arp协议,如图绿色。在交换机处做广播操作,发给计算机2和路由器
-
计算机2识别目标ip不是自己,直接丢弃。路由器识别包,然后还是用arp协议如图黄色。返回给计算机1
-
做完1,2步操作,那么计算机1的就有一个gateway->mac地址。
-
当计算机1应用层发出http请求,那么会在传输控制层进行3次握手,进行3次握手时也要发包操作
-
向目标ip:192.168.3.4,端口80申请握手,先用192.168.3.4&mask计算出的值与des对比,如果相同就用当前条目的gw,例子中匹配了gateway=192.168.1.1,然后这个gateway对应了一个mac地址,那么包装形如
{ "mac":"xxxxx", "ip":"xxxx", "port":"xxxxx" }
向外发送
-
mac地址解决节点的跳跃问题,而ip可以找出下一跳的地址,port找到最终处理的程序。
最后
该文章多处参考【捡田螺的小男孩】,特别鸣谢。
网友评论