005-TCP传输控制协议
一、概述
传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据包协议(UDP)是同一层内另一个重要的传输协议。
在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
数据在TCP层称为Stream,数据分组称为分段(Segment)。作为比较,数据在IP层称为Datagram,数据分组称为分片(Fragment)。 UDP 中分组称为Message。
数据帧(Frame):是一种信息单位,它的起始点和目的点都是数据链路层。
数据包(Packet):也是一种信息单位,它的起始和目的地是网络层。
数据报(Datagram):通常是指起始点和目的地都使用无连接网络服务的的网络层的信息单元。
段(Segment):通常是指起始点和目的地都是传输层的信息单元。
数据链路层的PDU叫做Frame(帧);
网络层的PDU叫做Packet(数据包);
TCP的叫做Segment(数据段);
二、TCP整体,三次握手,四次挥手
2.1、tcp/ip整体概述
通过上图可以看到
2.2、TCP协议头
2.3、详细概述
源端口(16位,2字节):发送端应用程序的端口号,与源IP地址确定一个唯一地址
目的端口(16位):接收端计算机应用程序的端口号,与目的IP地址确定唯一的地址
序列号(seq,32位长):TCP是面向字节流传输的,他为每一个字节编了一个序号,该报文段中序号为传输数据第一个字节的序号,例如:一个报文端的数据部分大小为100个字节,他的序号为400,那么下一次报文段的序号就为500
如果含有同步化旗标(SYN),则此为最初的序列号;第一个数据比特的序列码为本序列号加一。
如果没有同步化旗标(SYN),则此为第一个数据比特的序列码。
确认号(ack,32位长):指明了下一个期待接收的字节序号,表明该序号之前的所有字节都正确接收到了,只有当ACK为1的时候确认号才有效
数据偏移/首部长度(4个字节): 用来表示报文段数据的起始处距离报文起始处的长度也就是TCP报文首部的长度,由于首部含有可选项,所以TCP报头长度是不确定的。
保留:须置0
标志符
URG紧急控制位:与紧急指针配合使用,当URG为1的时候,就是通知系统这个报文段有紧急数据,需要优先传输。紧急指针字段有效。
ACK确认控制位:当他为1的时候,确认号字段才有效,TCP规定,在连接建立后,所有ACK都应该置为1
PSH推送控制位:当报文段的psh为1的时候,接收方接到该报文段,就立刻将他交付给接收应用进程,而不是等待缓冲区装满的时候再交付。
RST复位控制位:当报文段的RST为1的时候,说明该TCP连接出现错误,必须释放连接,并重新建立连接。还可以用于拒绝非法的报文段和拒绝连接请求。
SYN同步控制位:在连接建立时用来同步序列号,当SYN=1,ACK=0时说明这是一个连接请求报文段,如果对方同意建立连接则应该在响应的报文段中将SYN=1,ACK=1,表示接受请求
FIN终止控制位:用来释放连接,当FIN=1时表示此报文段发送方的数据已经发送完毕,并要求释放连接。
窗口(WIN,16位长):表示从确认号开始,本报文的接受方可以接收的字节数,即接收窗口大小。用于流量控制。
校验和(Checksum,16位长):对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。这是一个强制性的字段。
紧急指针(16位长):本报文段中的紧急数据的最后一个字节的序号。
选项字段:最多40字节。每个选项的开始是1字节的kind字段,说明选项的类型。
0:选项表结束(1字节)
1:无操作(1字节)用于选项字段之间的字边界对齐。
2:最大报文段长度(4字节,Maximum Segment Size,MSS)通常在创建连接而设置SYN标志的数据包中指明这个选项,指明本端所能接收的最大长度的报文段。通常将MSS设置为(MTU-40)字节,携带TCP报文段的IP数据报的长度就不会超过MTU,从而避免本机发生IP分片。只能出现在同步报文段中,否则将被忽略。
3:窗口扩大因子(4字节,wscale),取值0-14。用来把TCP的窗口的值左移的位数,使窗口值乘倍。只能出现在同步报文段中,否则将被忽略。这是因为现在的TCP接收数据缓冲区(接收窗口)的长度通常大于65535字节。
4:sackOK—发送端支持并同意使用SACK选项。
5:SACK实际工作的选项。
8:时间戳(10字节,TCP Timestamps Option,TSopt)
发送端的时间戳(Timestamp Value field,TSval,4字节)
时间戳回显应答(Timestamp Echo Reply field,TSecr,4字节)
填充:这是为了使整个首部长度是 4 字节的整数倍
其他选项:
MSS最大报文段长度(Maxium Segment Size):指明自己期望对方发送数据字段的最大长度,如果未填写默认为536个字节,他只出现在SYN=1的报文段中。
窗口扩大选项:当出现宽带比较大的通信的时候,就需要扩大窗口来满足性能和吞吐量。占 3 字节,其中有一个字节表示移位值 S.新的窗口值等于TCP 首部中的窗口位数增大到(16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小
SACK选择确认项(Selective Acknowledgements):为了确保重传的时候只传丢失的那部分报文段,而不重传所有的报文段,最多能描述4个丢失的报文,接收方收到了和前面的字节流不连续的两2字节.如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据
时间戳选项(Timestamps):使用该字段就很容易区分相同序列号的不同报文段(回绕序列号),还可以计算RTT(往返时间),当发送端发送一个报文段的时候把当前时间放入这个时间戳选项,当接收方收到后将其复制到确认报文段,发送方接收到这个确认报文段后就可以计算往返时间了。占10 字节,其中最主要的字段时间戳值字段(4字节)和时间戳回送回答字段(4字节)
NOP(NO-Operation):指明选项部分的每种选项长度必须是4字节的倍数,不足时用NOP补充,同时他还可以用来分割不同的选项字段。
数据部分:该部分可选,列如,在一个链接建立和终止的时候,双方发送的报文段只有首部
2.4、三个阶段
2.4.1、链接建立【三次握手】
简述:A:嘿【syc】,B:嘿,收到了【syc,ACK】,A:好的【ack】
图解
过程:
1》c-s:客户端A 的 TCP 向服务端 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x
客户端进入SYN_SEND状态,等待服务器的确认;
2》s-c:服务端B 的 TCP 收到连接请求报文段后,如同意,则发回确认(服务端B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x﹢1,自己选择的序号 seq = y)
服务器进入SYN_RECV状态;
3》c-s:客户端A 收到此报文段后向 服务端B 给出确认,其 ACK = 1,确认号 ack = y﹢1(客户端A 的 TCP 通知上层应用进程,连接已经建立,服务端B 的 TCP 收到客户端主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立)
客户端和服务器端都进入ESTABLISHED状态
至此完成三次握手,可以进入下一阶段
2.4.2、数据传送
2.4.3、连接释放【四次挥手】
简述:A:传完了【FIN=1】,B:嗯【ack】,B:那我关了啊【ack,FIN】,A:好的【ack】
图解:
步骤:
tcp四次挥手,由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
1》客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)(A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认)
主机A进入FIN_WAIT_1状态;这表示主机A没有数据要发送给主机B了;
2》B 发出确认,确认号 ack = u+1,而这个报文段自己的序号 seq = v(TCP 服务器进程通知高层应用进程.从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态.B 若发送数据,A 仍要接收)
主机A进入FIN_WAIT_2状态;主机B告诉主机A,我也没有数据要发送了,可以进行关闭连接了;
3》主机B向主机A发送FIN报文段,请求关闭连接,同时主机B进入CLOSE_WAIT状态;若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接
4》A 收到连接释放报文段后,必须发出确认,在确认报文段中 ACK = 1,确认号 ack=w﹢1,自己的序号 seq = u + 1
TCP采用四次挥手关闭连接如图所示为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
更多扩展:https://www.cnblogs.com/yueminghai/p/6646043.html
三、使用wireshark抓包分析
1、配置wireshark抓取本地回环网络:
2、抓取记录
分析:【三次握手,四次挥手】
123行:客户端发起第一次请求;第一次握手
124行:服务端回复ack请求:第二次握手
125行:客户端回复ack请求:第三次握手
握手结束,127行开始数据传输;
客户端结束ack发起
315行:客户端发起结束ack请求,第一次挥手
316行:服务端回复结束ack请求,第二次挥手
服务端结束ack发起
317行:服务端发起结束ack请求,第三次挥手
318行:客户端回复结束ack请求,第四次挥手
可以看到126行是服务端发起的请求
TCP Window Full:
接收方接收缓冲区满了后,导致发送方的发送缓冲区装满待确认数据,此时发送方会发送一个TCP Window Full消息。
TCP ZeroWindow:
接收方应用没有及时recv消息,导致接收缓冲满,即滑动窗口为0,接收方发送TCP Zero Window告知发送方不能继续发送消息。
TCP ZeroWindowProbe:
零窗口探测报文---滑动窗口降为0后,发送方会停止发送数据,但此时如果发送有数据待发送,发送方发送TCP ZeroWindowProbe包,主动获取接收方滑动窗口的最新值。
TCP Window Update:
滑动窗口为0后,发送方停止发送数据,如果接收方滑动窗口出现空闲空间,则接收方主动发送TCP Window Update来更新发送方的滑动窗口。
MSS:
TCP层支持的最大分包字节数,以太网的电气性能决定了该值为1460字节,ethernet层的MTU值最大1500字节,除去IP头20字节、TCP头20字节。
更多原理级介绍:
https://coolshell.cn/articles/11564.html
3.1、一次请求消息查看
或者
分析
Frame:物理层的数据帧概况;
EthernetⅡ:数据链路层以太网帧头部信息;
Internet Protocol Version 4:互联网层IP包头部;
Transmission Control Protocol:传输层的数据段头部信息
Hypertext Transfer Protocol:应用层的信息,这里的是HTTP;
1、Frame 物理层数据帧
Frame 29: 213 bytes on wire (1704 bits), 213 bytes captured (1704 bits) on interface 0
#29号帧,线路213个字节,实际捕获213个字节#
Interface id: 0 (\Device\NPF_{2214FA8C-274A-4657-B257-F1BB47FFAB8D})
#接口ID#
Encapsulation type: Ethernet (1)
#封装类型#
Arrival Time: Jan 17, 2017 15:16:14.822720000 中国标准时间
#捕获的日期和时间#
[Time shift for this packet: 0.000000000 seconds]
#此数据包的时间偏移#
Epoch Time: 1484637374.822720000 seconds
#周期时长#
[Time delta from previous captured frame: 0.001654000 seconds]
#此数据包与前一个数据包的捕获时间间隔#
[Time delta from previous displayed frame: 0.001654000 seconds]
#此数据包与前一个数据包的显示时间间隔#
[Time since reference or first frame: 2.089471000 seconds]
#此数据包与第一个数据包的时间间隔#
Frame Number: 29
#帧序号#
Frame Length: 213 bytes (1704 bits)
#帧长度#
Capture Length: 213 bytes (1704 bits)
#捕获长度#
[Frame is marked: False]
#此帧是否被标记#
[Frame is ignored: False]
#此帧是否被忽略#
[Protocols in frame: eth:ethertype:ip:tcp:http]
#帧内封装的协议层次结构#
[Coloring Rule Name: HTTP]
#着色标记的协议名称#
[Coloring Rule String: http || tcp.port == 80 || http2]
#着色规则显示的字符串#
2、数据链路层
Ethernet II, Src: Tp-LinkT_80:37:36 (ec:26:ca:80:37:36), Dst: 58:00:e3:47:ad:e1 (58:00:e3:47:ad:e1)
#以太网帧,源地址:ec:26:ca:80:37:36,目的地址:58:00:e3:47:ad:e1#
Destination: 58:00:e3:47:ad:e1 (58:00:e3:47:ad:e1) #目标Mac地址#
Source: Tp-LinkT_80:37:36 (ec:26:ca:80:37:36) #源Mac地址#
Type: IPv4 (0x0800) #类型#
3、IP 网络层
Internet Protocol Version 4, Src: 101.226.89.30, Dst: 192.168.1.104
Version: 4 #互联网协议IPv4#
Header Length: 20 bytes #IP包头部长度#
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT) #差分服务字段#
Total Length: 199 #IP包的总长度#
Identification: 0x76ae (30382) #标志字段
Flags: 0x02 (Don't Fragment) #标记字段#
Fragment offset: 0 #分的偏移量#
Time to live: 50 #生存期TTL#
Protocol: TCP (6) #此包内封装的上层协议为TCP#
Header checksum: 0x5072 [validation disabled] #头部的数据校验和#
Source: 101.226.89.30 #源IP地址#
Destination: 192.168.1.104 #目的IP地址#
Source GeoIP: Unknown #源地理位置#
Destination GeoIP: Unknown #目的地理位置#
4、TCP传输层
Transmission Control Protocol, Src Port: 80 (80), Dst Port: 50054 (50054), Seq: 1, Ack: 624, Len: 159
#TCP头部信息,源端口号:80,目的端口号:50054,序列号:1,确认序列号:624,下一个序列号:160#
Source Port: 80 #源端口号#
Destination Port: 50054 #目的端口号#
Sequence number: 1 (relative sequence number) #序列号 (相对序列号)#
[Next sequence number: 160 (relative sequence number)] #下一个序列号#
Acknowledgment number: 624 (relative ack number) #确认序列号#
Header Length: 20 bytes #头部长度#
Flags: 0x018 (PSH, ACK) #TCP标记字段#
Window size value: 33 #流量控制的窗口大小#
Checksum: 0x639e [validation disabled] #TCP数据段的校验和#