目录
一、前言
两台主机间通信,通常是指两台主机间的进程进行通信。在TCP/IP模型中,运输层的目的就是为应用进程之间提供端到端的逻辑通信,运输层通过端口号区分不同的应用进程,并提供一些运输层协议。其中,运输层最常见的两种协议便是TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据报协议)。
TCP 和UDP是传输层的两个重要协议,我们平常浏览网页,手机聊天,观看视频都是通过这两种协议进行传输的。本文将从头部格式、连接管理、 可靠性等角度分析两者区别。
二、TCP与UDP区别
2.1 头部格式
2.1.1 TCP头部格式
源端口号(16位) | 目标端口号(16位) | |||||||
序列号(32位) | ||||||||
确认应答号(32位) | ||||||||
首部长度 (4位) | 保留 (6位) | U R G | A C K | P S H | R S T | S Y N | F I N | 窗口大小(16位) |
校验和(16位) | 紧急指针(16位) | |||||||
选项(长度可变) | ||||||||
数据 |
由上图可以看出,TCP头部字段最少为20字节,其中核心字段如下所示。
序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
控制位:
• ACK:该位为 1 时,「确认应答」的字段变为有效。
• RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
• SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
• FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。
2.1.2 UDP头部格式
由于UDP 不提供复杂的控制机制,UDP 协议也非常简单,头部只有 8
个字节( 64 位),如下图所示。
源端口号(16位) | 目标端口号(16位) |
包长度(16位) | 校验和(16位) |
数据 |
目标和源端口号:主要是告诉 UDP 协议应该把报文发给哪个进程。
包长度:该字段保存了 UDP 首部的长度跟数据的长度之和。
校验和:校验和是为了提供可靠的 UDP 首部和数据而设计,防止收到在网络传输中受损的 UDP包。
2.2 连接管理
2.2.1 TCP
TCP是面向连接的,每次传输数据前进行三次握手建立连接,数据传输完成后四次挥手断开连接。
TCP三次握手
TCP三次握手具体流程如下所示:
Step1: 一开始,客户端和服务端都处于 CLOSE
状态。先是服务端主动监听某个端口,处于 LISTEN
状态;
Step2: 客户端会随机初始化序号(client_isn
),将此序号置于 TCP 首部的「序号」字段中,同时把 SYN
标志位置为 1
,表示 SYN
报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,之后客户端处于 SYN_SENT
状态;
Step3: 服务端收到客户端的 SYN
报文后,服务端也随机初始化自己的序号(server_isn)
,将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入 client_isn + 1
, 接着把 SYN
和 ACK
标志位置为 1
。最后把该报文发给客户端,之后服务端处于 SYN_RCVD
状态;
Step4: 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部 ACK
标志位置为 1
,其次「确认应答号」字段填入 server_isn + 1
,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于 ESTABLISHED
状态;
Step5: 服务端收到客户端的应答报文后,也进入 ESTABLISHED
状态。
TCP四次挥手
TCP四次挥手具体流程如下所示:
Step1: 客户端打算关闭连接,此时会发送一个 TCP 首部 FIN
标志位被置为 1
的报文,也即 FIN
报文,之后客户端进入 FIN_WAIT_1
状态;
Step2: 服务端收到报文后,向客户端发送 ACK
应答报文,服务端进入 CLOSE_WAIT
状态;
Step3: 客户端收到服务端的 ACK
应答报文后,之后进入 FIN_WAIT_2
状态;
Step4: 等待服务端处理完数据后,向客户端发送 FIN
报文,之后服务端进入 LAST_ACK
状态;
Step5: 客户端收到服务端的 FIN
报文后,回复一个 ACK
应答报文,之后进入 TIME_WAIT
状态;
Step6: 服务端收到了 ACK
应答报文后,就进入了 CLOSE
状态,至此服务端已经完成连接的关闭;
Step7: 客户端在经过 2MSL
一段时间后,自动进入 CLOSE
状态,至此客户端也完成连接的关闭。
2.2.2 UDP
由上图可知,UDP协议是面向无连接的。当使用UDP协议时,发送端的应用层将数据传递给运输层,UDP只会给数据增加一个UDP头,标识是UDP协议,然后就传递给网络层了。在接收端,网络层将数据传递给传输层,UDP只去除IP报文头就传递给应用层了,不做任何拼接操作。即UDP协议是面向报文的。
2.3 可靠性
2.3.1 TCP可靠性
虽然IP协议提供的是无连接不可靠服务,但只要运输层提供TCP协议,就能提供可靠的传输服务。
发送方向接收方发送报文段,接收方收到报文段后,根据首部中的校验和字段的值检测该报文段是否产生误码,若没有产生误码则收下该报文段并回复确认报文,若产生误码则直接丢弃该报文并且不发送确认报文段,从而触发TCP的超时重传机制。若发送方向接收方发送报文段时,该报文在传输过程中被丢弃了,这也会触发超时重发机制。
因此,无论发送方发送的数据包在传输过程中遇到了什么情况(丢包、误码),收发双发只要使用TCP协议,接收方最终都可以正确接收到该数据包。TCP适用于要求可靠传输的服务,如文件传输等服务。
2.3.2 UDP可靠性
IP协议向其上层提供的是无连接不可靠服务, 而UDP也是提供不可靠传输服务,若传输过程中产生误码,接收方UDP可通过数据报首部中的校验和字段的值检测到产生误码的情况 ,但并不会对该误码报文做出处理。同样地,若发送方发送的报文在传输过程中丢失了,发送方也不会做任何处理。因此,UDP只保证尽最大努力交付,而不考虑数据报是否安全达到,适用于实时应用,如IP电话,远程视频等。
2.4 服务对象
TCP 是一对一的两点服务,即一条连接只有两个端点,UDP 支持一对一、一对多、多对多的交互通信。
三、Wireshark抓包
3.1 TCP抓包
3.1.1 TCP三次握手抓包
由于HTTP服务是基于TCP协议的,本例中我们用本地主机(192.168.0.102)访问https://www.baidu.com(180.101.49.13)来抓取TCP报文。抓取到的三次握手报文如下:
第一握手:客户端发送一个TCP数据报,标志位为SYN,序列号为0, 代表客户端请求建立连接,如下图所示:
第二次握手:服务器发回确认包, 标志位为 SYN,ACK。将确认序号(Acknowledgement Number)设置为客户的序号seq(Sequence number)加1,并将序列号设置为0。即0+1=1,如下图所示:
第三次握手:客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1,并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方。在进过三次握手后和服务器建立了TCP连接,如下图所示
3.1.2 TCP四次挥手
第一次挥手:由客户端发起,序列号Seq为365,ACK为584。
理论上第一次挥手应为FIN包,但实际抓包确实FIN+ACK包,这是因为TCP报文是一个可靠的协议,它对每一个数据包都要进行确认,每发一个数据包都有一个对应的ACK包来确认一下,因此这里的ACK标识位其实是对上一个报文数据的确认。
第二次挥手+第三次挥手:服务器给客户端回应确认消息并且发送FIN报文,Seq为584,ACK为366
这里之所以没有想象中的两次分开挥手,是因为开启了延时ACK机制 ,在收到第一个FIN之后,导致ACK的发送被延时了,在延时的过程中,应用如果确认没数据要发,并且也要关闭此连接的情况下,会触发发送FIN,这个FIN就会和之前的ACK合并被发出。
第四次挥手:客户端向服务器发送最后的ACK报文,此时Seq为366,ACK为585。
3.2 UDP抓包
四、总结
TCP | UDP | |
首部开销 | 最少为20字节 | 固定为8字节 |
连接管理 | 面向连接 | 不需要连接 |
可靠性 | 可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达 | 尽最大努力交付,不保证可靠交付数据 |
服务对象 | 一对一 | 一对一、一对多、多对多 |
传输方式 | 基于字节流 | 基于数据报 |