TCP简介(网络基础中有所介绍)
TCP传输控制协议:
- 面向连接、可靠的、基于字节流的传输层协议
- 将应用层的数据分割成报文段并发送给目标节点TCP层
- 数据包都是有序号的,对方收到则发送ACK确认,未收到则重传
- 使用校验和函数来检验数据在传输过程中是否有误
TCP报文头
其中 ACK SYN 序号 这三个部分在以下会用到,它们的介绍也在下面

上面就是TCP协议头部的格式,由于它比较重要,是理解其它内容的基础,下面就将每个字段的信息都详细的说明一下。
- Source Port和Destination Port:分别占用16位,表示
源端口号和目的端口号;用于区别主机中的不同进程,而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接; - Sequence Number:用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号,主要用来解决
网络报文乱序的问题; - Acknowledgment Number:32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
- Offset:给出首部中32 bit字的数目,需要这个值是因为任选字段的长度是可变的。这个字段占4bit(最多能表示15个32bit的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。然而,没有任选字段,正常的长度是20字节;
TCP Flags
- URG:紧急指针标志
ACK:确认序号标志- PSH:push标志
- RST:重置连接标志
SYN:同步序号,用于建立连接FIN:finish标志,用于释放连接
3个红色的flag是常用标志
TCP三次握手
tcp需要经过三次握手来建立全双工(允许数据在两个方向上同时传输)连接:

seq是上方介绍的Sequence Numberack,小写的ack是上方的Acknowledgment Numbe
- 第一次握手:客户端发送连接请求报文段,将SYN为1,Sequence Number为
J,然后客户端进入SYN_SEND状态,等待服务器的确认 - 第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置
Acknowledgment Number(ack)为J+1;同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为K;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态; - 第三次握手:客户端收到服务器的SYN+ACK报文段。然后将
Acknowledgment Number设置为K+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。这样就完成了连接。
为何需要三次握手才能建立连接
- 主要就是初始化Sequence Number,也就是上面中的
J和K,通讯双方都将获取对方的这个序号,以保证应用层不回因为网络问题而乱序,即TCP会用这个序号拼接数据。 - 第一次客户端发送给服务端,服务端收到了就第二次握手发送消息给客户端,如果到这儿就结束了,也就是两次握手,那么服务端并不能确认它发出的消息客户端有没收到,所有需要第三次客户端在此发送消息给服务端,你的消息我收到了,这样双方才能确认彼此都能收到对方的消息,连接也就建立起了。
首次握手的隐患:SYN超时:
- Server收到Client的SYN,回复SYN-ACK的时候未收到ACK确认(此时Client掉线)
- Server不断重试直至超时,Linux默认等待63秒才断开连接
针对SYN Flood的防护措施(遭遇网络攻击恶意占用连接通道):
- SYN队列满后,通过tcp_syncookies参数回发SYN Cookie,若是正常连接则Client会回发SYN Cookie,直接建立连接
建立连接后,Client出现故障
- 保活机制:向对方发送保活探测报文,如果未收到则继续发送,次数达到保活探测数后仍未收到响应则中断
TCP四次挥手
tcp通过四次挥手来断开连接:

挥手过程
- 第一次挥手: 主动关闭方(可以使客户端,也可以是服务器端,这里标记为:A),A发送一个FIN,用来关闭A到B的数据传输,A进入FIN_WAIT_1
- 第二次挥手:B收到FIN后,发送一个ACK给A,确认序号(ack)为收到的序号+1(与SYN相同,一个FIN占用一个序号),B进入CLOSE_WAIT状态(还可以进行数据传送)
- 第三次挥手:B发送一个FIN,用来关闭A到B的数据传送,B进入到LAST_ACK状态
- 第四次挥手:A收到B发送的FIN报文段,进入TIME_WAIT状态,接着发送一个ACK给B确认序号(ack)为收到的序号+1,B在收到报文后进入CLOSED状态,A在发送完报文等待了
2MSL时间后进入CLOSED状态。
为什么会有TIME_WAIT状态(为什么等待2MSL):
- 确保有足够的时间让对方收到ACK包(如果对方没有收到,对方会再次进行第三次挥手,这样一来一回的时间就是2*MSL了)
- 避免新旧连接混淆(有些路由器会缓存ip数据包,如果连接被重用,那么延迟收到的包有可能跟新连接混到一起)
为什么需要四次挥手才能断开连接
- 因为全双工,发送方和接收方都需要FIN报文和ACK报文。
服务器大量出现CLOSE_WAIT状态的原因 对方关闭socket连接,我放忙于读或写,没有及时关闭连接
- 检测代码,特别是释放资源代码
- 检测配置,特别是处理请求的线程配置
UDP简介
报文结构

- 面向非连接
- 不维护连接状态,支持同时向多个客户端传输相同的消息
- 数据包报头只有8个字节,额外开销小
- 吞吐量只受限于数据生成速率,传输速率以及机器性能
- 尽最大努力交付,不保证可靠交付,不需要维持复杂的连接状态表
- 面向报文,不对应用程序提交的报文信息进行拆分或者合并
UDP与TCP的区别
- TCP面向连接vs无连接
- 可靠性:TCP通过三次握手保证,UDP可能丢包
- 有序性:TCP最终会进行排序(Sequence Number)
- 速度:TCP较慢
- 量级:TCP是重量级的,UDP是轻量级