运输层协议(UDP与TCP)详解以及wireshark抓包工具的使用

目录

[一. 数据包的封装](#一. 数据包的封装)

[1.1 数据包封装过程](#1.1 数据包封装过程)

[二. UDP协议](#二. UDP协议)

[2.1 UDP的主要特点](#2.1 UDP的主要特点)

[2.2 UDP数据包格式](#2.2 UDP数据包格式)

[2.3 使用wireshark进行抓包分析](#2.3 使用wireshark进行抓包分析)

[三. TCP协议](#三. TCP协议)

[3.1 TCP的主要特点](#3.1 TCP的主要特点)

[3.2 TCP连接](#3.2 TCP连接)

[3.3 TCP数据包格式](#3.3 TCP数据包格式)

[3.4 TCP通信时许](#3.4 TCP通信时许)

[3.4.1 TCP建立连接过程--三次握手](#3.4.1 TCP建立连接过程--三次握手)

[3.4.2 TCP释放连接过程--四次挥手](#3.4.2 TCP释放连接过程--四次挥手)

半关闭状态

[3.5 使用wireshark抓包分析](#3.5 使用wireshark抓包分析)

[3.5.1 三次握手抓包分析](#3.5.1 三次握手抓包分析)

[3.5.2 数据传输抓包分析](#3.5.2 数据传输抓包分析)

客户端向服务端发送:

服务端向客户端发送:

[3.5.3 四次挥手抓包分析](#3.5.3 四次挥手抓包分析)

[3.5.4 整体流程:](#3.5.4 整体流程:)

[3.6 滑动窗口机制](#3.6 滑动窗口机制)


一. 数据包的封装

1.1 数据包封装过程

传输层及其以下的机制由内核 提供,应用层由用户进程提供,应用程序对通讯数据的含义进行解释,而传输层及其以下处理通讯的细节,将数据从一台计算机通过一定的路径发送到另一台计算机。应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如下图所示:

不同的协议层对数据包有不同的称谓,在传输层叫做段(segment) ,在网络层叫做数据报(datagram) ,在链路层叫做帧(frame)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理。

目的主机收到数据包后,如何经过各层协议栈最后到达应用程序呢?其过程如下图所示:

二. UDP协议

2.1 UDP的主要特点

(1)UDP是无连接的,即发送数据之前不需要建立连接(当然发送数据结束时也没有连接可释放),因此减少了开销和发送数据之前的时延。

(2)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的连接状态表(这里面有许多参数)。

(3)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。这就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文,如图所示。在接收方的UDP,对IP层交上来的UDP用户数据报,在去除首部后就原封不动地交付给上层的应用进程。也就是说,UDP一次交付一个完整的报文。因此,应用程序必须选择合适大小的报文。若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率。反之,若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率。

(4)UDP没有拥塞控制,因此网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的。很多的实时应用(如IP电话、实时视频会议等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延。UDP正好适合这种要求。

(5)UDP支持一对一、一对多、多对一和多对多的交互通信

(6)UDP的首部开销小 ,只有8个字节比TCP的20个字节的首部要短 。虽然某些实时应用需要使用没有拥塞控制的UDP,但当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。因此,不使用拥塞控制功能的UDP有可能会引起网络产生严重的拥塞问题。

2.2 UDP数据包格式

用户数据报UDP有两个字段:数据字段和首部字段 。首部字段只有8个字节),由四个字段组成,每个字段的长度都是两个字节。各字段意义如下:

(1)源端口 -----在需要对方回信时选用。不需要时可用全0。

(2)目的端口 -----这在终点交付报文时必须要使用到。

(3)长度 -----数据+首部,其最小值是8(仅有首部)

(4)检验和-----检测UDP用户数据报在传输中是否有错。有错就丢弃。

2.3 使用wireshark进行抓包分析

启动 wireshark 命令

bash 复制代码
sudo wireshark

抓包分析:

可以看到一个进程向另一个进程发送了一个"hello",

源端口为:35131 目的端口为:50000

长度为:13 = 5 + 8 校验和:0xfe20

数据:68656c6c6f:hello

三. TCP协议

3.1 TCP的主要特点

(1)TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放已经建立的TCP连接。这就是说,应用进程之间的通信好像在"打电话":通话前要先拨号建立连接,通话结束后要挂机释放连接。

(2)每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一)。

(3)TCP提供可靠交付的服务。也就是说,通过TCP连接传送的数据,无差错、不丢失、不重复、并且按序到达。

(4)TCP提供全双工通信 。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。

(5)面向字节流。 TCP 中的"流"(stream)指的是流入到进程或从进程流出的字书序列。"面向字节流"的含义是:虽然应用程序和TCP的交互是一次一个数据块(大小不等),但TCP把应用程序交下来的数据看成仅仅是一连串的无结构的字节流。TCP并不知道所传送的字节流的含义。TCP不保证接收方应用程序所收到的数据块和发送方应用程序所发出的数据块具有对应大小的关系**(例如,发送方应用程序交给发送方的TCP共10个数据块,但接收方的TCP可能只用了4个数据块就把收到的字节流交付给了上层的应用程序)**。但接收方应用程序收到的字节流必须和发送方应用程序发出的字节流完全一样。当然,接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。

3.2 TCP连接

TCP把连接作为最基本的抽象。TCP的许多特性都与TCP是面向连接的这个基本特性有关。因此我们对TCP连接需要有更清楚的了解。前面已经讲过,每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是运输层的协议端口。TCP连接的端点叫做套接字(socket)或插口。根据RFC793的定义:端口号拼接到(contatenated with)IP地址即构成了套接字。因此套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。例如,若IP地址是192.3.4.5而端口号是80,那么得到的套接字就是(192.3.4.5:80)。总之:

套接字 socket = (IP地址:端口号)

每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定。即:

TCP 连接 = ( socket, socket2 ) = { (IPi:port), (IP2: port) }

3.3 TCP数据包格式

TCP报文段首部的前20个字节是固定的,后面有4N字节是根据需要而增加的选项(N是整数)。因此TCP首部的最小长度是20字节。首部固定部分各字段的意义如下:

**(1)源端口和目的端口:**各占2个字节,分别写入源端口号和目的端口号。

(2)序号: 占4字节。序号范围是0,2\^32 - 1共4284967296个序号 。序号增加到2^32-1后,下一个序号就又回到0。也就是说,序号使用mod 2^32 运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号字段值是301,而携带的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的名称也叫做"报文段序号"

(3)确认号: 占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。若确认号=N,则表明:到序号N-1为止的所有数据都已正确收到。

(4)数据偏移:占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出 TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的。但请注意,"数据偏移"的单位是32位字(即以4字节长的字为计算单位)。由于4位二进制数能够表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大长度(即选项长度不能超过40字节)。

**(5)保留:**占6位,保留为今后使用,但目前应置为0。

**(6) 标志位:**占6位

|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| URG | 当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。当URG置1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。 |
| ACK | 仅当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1。 |
| PSH | 当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满了后再向上交付。 虽然应用程序可以选择推送操作,但推送操作还很少使用。 |
| RST | 当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。 |
| SYN | 在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文。 |
| FIN | 用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。 |

(7)窗口: 占2字节。窗口值是**0,2\^16- 1** 之间的整数(65535)。窗口指的是发送本报文段的接收窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。窗口字段明确指出了现在允许对方发送的数据量。窗口值是经常在动态变化着。

**(8)检验和:**占2字节

**(9)紧急指针:**占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据)。因此紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为零时也可发送紧急数据。

**(10)选项:**长度可变,最长可达40字节。当没有使用选项时,TCP的首部长度是20字节

3.4 TCP通信时许

3.4.1 TCP建立连接过程--三次握手

三次握手:

(1) A的TCP客户进程向B发出连接请求报文段,这时首部中的同步位SYN=1,同时选择一个初始序号seq=x。TCP规定,SYN报文段(即SYN=1的报文段)不能携带数据,但要消耗掉一个序号。 这时,TCP客户进程进入**SYN-SENT.(同步已发送)**状态

(2) B收到连接请求报文段后,如同意建立连接,则向A发送确认。在确认报文段中应把SYN位和ACK位都置1,确认号是ack=x+1,同时也为自己选择一个初始序号seq=y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。 这时TCP服务器进程进入SYN-RCVD(同步收到)状态。

(3) TCP客户进程收到B的确认后,还要向B给出确认。确认报文段的ACK置1,确认号ack=y+1,而自己的序号seq=x+1。TCP的标准规定,ACK报文段可以携带数据。但如果不携带数据则不消耗序号,在这种情况下,下一个数据报文段的序号仍是seq=x+1。 这时,TCP连接已经建立,A进入ESTABLISHED(已建立连接)状态

3.4.2 TCP释放连接过程--四次挥手

(1) 数据传输结束后,通信的双方都可释放连接。现在A和B 都处于ESTABLISHED 状态。A的应用进程先向其TCP发出连接释放报文段,并停止再发送数据,主动关闭TCP连接。A把连接释放报文段首部的FIN置1,其序号seq=u,它等于前面已传送过的数据的最后一个字节的序号加1。 这时A进入FIN-WAIT-1(终止等待1)状态,等待B的确认。请注意,TCP规定,FIN报文段即使不携带数据,它也消耗掉一个序号。

(2) B收到连接释放报文段后即发出确认,确认号是ack=u+1,而这个报文段自己的序号是v,等于B前面已传送过的数据的最后一个字节的序号加1。 然后B就进入CLOSE-WAIT(关闭等待)状态。TCP服务器进程这时应通知高层应用进程,因而从A到B这个方向的连接就释放了,**这时的TCP连接处于半关闭(half-close)状态,即A已经没有数据要发送了,但B若发送数据,A仍要接收。**也就是说,从B到A这个方向的连接并未关闭。这个状态可能会持续一些时间。

(3) 若B已经没有要向A发送的数据,其应用进程就通知TCP释放连接。**这时B发出的连接释放报文段必须使FIN=1。现假定B的序号为w(在半关闭状态B可能又发送了一些数据)。B还必须重复上次已发送过的确认号ack=u+1。**这时B就进入LAST-ACK(最后确认)状态,等待A的确认。

(4) A在收到B的连接释放报文段后,必须对此发出确认。**在确认报文段中把ACK置1,确认号ack=w+1,而自己的序号是seq=u+1(根据TCP标准,前面发送过的FIIN报文段要消耗一个序号)。**然后进入到TIME-WAIT(时间等待)状态。请注意,现在TCP连接还没有释放掉。必须经过时间等待计时器(TIME-WAITtimer)设置的时间2MSL后,A才进入到 CLOSED 状态。

半关闭状态

关闭的只是发送数据的缓冲区,ACK应答标志位还是可以发送的!!!

3.5 使用wireshark抓包分析

3.5.1 三次握手抓包分析

第一次:客户端向服务端: sequenc number:0 SYN:1

ACK number= 0

第二次:服务端向客户端: sequenc number:0 SYN:1 ACK:1

ACK number= 1

第三次:客户端向服务端: sequenc number:1(SYN标志位要消耗一个序号) ACK:1

ACK number= 1

3.5.2 数据传输抓包分析

客户端向服务端发送:

客户端向服务端:sequence number=1(上一个ACK未携带数据,不消耗序号)

ACK number= 1

ACK = 1

服务端回给客户端:sequence number=1(上一个ACK未携带数据,不消耗序号)

ACK number= 6(客户端发给服务端的数据长度是5,希望收到的下一个数据的序号是6)

ACK = 1

服务端向客户端发送:

服务端向客户端:sequence number=1(上一个ACK未携带数据,不消耗序号)

ACK = 1

ACK number= 6(客户端发给服务端的数据长度是5,希望收到的下一个数据的序号是6)

客户端回服务端:sequence number=6

ACK number= 10(服务端发给客户端的数据长度是9,希望收到的下一个数据的序号是10)

ACK = 1

3.5.3 四次挥手抓包分析

客户端请求断开连接:sequence number=6

ACK number = 10

ACK = 1

FIN = 1(注意:FIN不携带数据也消耗序号)

服务端回复给客户端:sequence number=10

ACK number= 7

ACK = 1

FIN = 1(注意:FIN不携带数据也消耗序号)

客户端回复给服务端:sequence number=7

ACK number= 11

ACK = 1

3.5.4 整体流程:

3.6 滑动窗口机制

介绍UDP时我们描述了这样的问题:如果发送端发送的速度较快,接收端接收到数据后处理的速度较慢,而接收缓冲区的大小是固定的,就会丢失数据。TCP协议通过"滑动窗口(Sliding Window)"机制解决这一问题。看下图的通讯过程:

  1. 发送端发起连接,声明最大段尺寸是1460,初始序号是0,窗口大小是4K,表示"我的接收缓冲区还有4K字节空闲,你发的数据不要超过4K"。接收端应答连接请求,声明最大段尺寸是1024,初始序号是8000,窗口大小是6K。发送端应答,三方握手结束。
  2. 发送端发出段4-9,每个段带1K的数据,发送端根据窗口大小知道接收端的缓冲区满了,因此停止发送数据。
  3. 接收端的应用程序提走2K数据,接收缓冲区又有了2K空闲,接收端发出段10,在应答已收到6K数据的同时声明窗口大小为2K。
  4. 接收端的应用程序又提走2K数据,接收缓冲区有4K空闲,接收端发出段11,重新声明窗口大小为4K。
  5. 发送端发出段12-13,每个段带2K数据,段13同时还包含FIN位。
  6. 接收端应答接收到的2K数据(6145-8192),再加上FIN位占一个序号8193,因此应答序号是8194,连接处于半关闭状态,接收端同时声明窗口大小为2K。
  7. 接收端的应用程序提走2K数据,接收端重新声明窗口大小为4K。
  8. 接收端的应用程序提走剩下的2K数据,接收缓冲区全空,接收端重新声明窗口大小为6K。
  9. 接收端的应用程序在提走全部数据后,决定关闭连接,发出段17包含FIN位,发送端应答,连接完全关闭。

上图在接收端用小方块表示1K数据,实心的小方块表示已接收到的数据,虚线框表示接收缓冲区,因此套在虚线框中的空心小方块表示窗口大小,从图中可以看出,随着应用程序提走数据,虚线框是向右滑动的,因此称为滑动窗口。