1. TCP基本介绍
1.1 TCP与OSI七层模型
如下图所示,L2为Ethernet II,L3为IPv4,L4为TCP,应用层为Telnet,至于最开始的Frame 242,是抓包软件wireshark加上去的,方便分析,在网络中传输时候是没有这部分的。
因此不难看出TCP协议位于OSI模型的第4层, 底层是IPv4/IPv6协议,上层是应用层协议,像TELNET、SSH、HTTP、SMTP、POP等。
1.2 TCP报头各个字段介绍
如下图所示,用wireshark对TCP的报头展开后,可以看到TCP的报头有哪些字段。
从上图中,我们没有看到TCP的版本字段,也就是说TCP没有版本之说。关于TCP各个字段,用一个表格来阐述。
字段名 | 长度 | 说明 |
Source Port | 2字节 | TCP的源端口口,一般是大于2014的随机端口 |
Destination Port | 2字节 | TCP的目的端口号,一般为知名端口号,当然这个取决于服务器侦听的端口 |
Sequence number | 4字节 | TCP对传输的数据先进行了分段, 然后给每一个段一个起始编号, 而且编号的最小单位是字节, 每一个TCP数据段的起始编号就是Sequence number |
Acknowledgment | 4字节 | 接收方每收到一段数据都会向发送方发送ACK标志位置1的相应TCP报文, 该报文中除了ACK标志置1以外, 确认序号(Acknowledgment)里面的值就是前面接收到数据的最后一个字节编号+1. |
Header Length | 4比特 | 单位是4字节,举例来说,如图该字段位1000(十进制为8),再乘4B,结果TCP报头长度为8*4B=32字节 |
Flags | 12比特 | 目前前3比特保留,值为000,后9比特都有定义,本图中SYN=1,其他都为0,表示这是TCP的第一个报文 |
Window size value | 2字节 | 报文发送方用此字段告诉接收方自己目前缓冲区最多能接收多少数据 |
Checksum | 2字节 | CRC校验和,用于检测TCP报头和TCP数据 |
Urgent pointer | 2字节 | |
Options | 4*(0--10)字节 | 比如本例中的 MSS:客户端和服务器协商各自支持的分段最大字节数, Window Scale:扩展Window Size,最终发送方接收窗口大小为 Window Size * (2 ^ Window Scale), SACK:双方协商是否支持选择确认机制,1--代表支持,0--代表不支持 |
2. Wireshark分析TCP协议
为了讲解TCP协议,我们抓取了一次完整的TCP包,该抓包取自的场景是:
在win10(ip:port=10.140.7.12:1036)上telnet到我的一台路由器(ip:port = 10.74.97.126:23),
然后根据提示输入账号cisco和密码cisco123!,进入到路由器的VTY界面,
最后,执行exit命令退出路由器VTY界面。
2.1 建立连接:三次握手
前三个报文:SYN、SYN/ACK、ACK,为TCP三次握手,用于建立连接。下图把这三个报文单独拿出来加以分析。
三次握手除了建立连接外,通信双方还协商了一些参数,如图中所示,这些参数有各自接收窗口大小Win,每次TCP最多传输的数据大小MSS等等。
其实除了双方交换数据外,各自还会有不同的状态机,如下图所示。
对客户端而言:
(1)当客户端程序有数据需要TCP传输时, 会通知客户端TCP发送SYN报文,然后从Closed状态迁移到SYN-SENT状态,
(2)一旦收到服务端TCP的SYN/ACK后,立即回复ACK报文,然后就进入到Established状态,表示可以向服务端发送数据。
对服务器而言:
(1)当服务端应用程序打开TCP端口之后,就从Closed状态切换到Listen状态,
(2)一旦收到客户端的SYN报文后, 立即回复SYN/ACK报文,然后进入到SYN-RCVD状态,
(3)如果收到客户端的ACK报文,就切换到Establed状态,表示可以发送数据给客户端。
2.2 数据传输:ACK机制
三次握手完成后,客户端和服务器都进入到Established状态,这时候双方开始交互数据。本例中从第4个报文到64个报文,都是相互交换数据。
No.4--No.4,telnet参数协商;No.5--No.64,服务器要求客户端输入账号和密码,客户端输入正确的账号和密码,登录到VTY界面,然后执行命令exit退出VTY界面。
在通信中,客户端每发送一定的数据给服务器后,服务器都会想要一个ACK报文,表示前面的数据都已经收到,同样的服务器每发送一定的数据给客户端后,客户端也会响应ACK报文。
这其实是TCP的一个可靠性保证机制,发送方用来确认数据的的确确到达接收方。
如果接收方没有回应ACK报文,这时候发送方会怎么处理呢?很简单就是重传,不过重传的机制很复杂,有超时重传、快速重传、选择重传,而且重传哪部分数据呢,是ACK之前的所有分段,还是丢失的那个字段?这些本文不作解释,以后再写一篇加以详细解释。
2.3 关闭连接:四次挥手
在VTY界面输入exit命令后,服务器就知道要关闭次连接,因此开始四次挥手:FIN、ACK、FIN/ACK、ACK来关闭连接。
上图中No.65并不是FIN,而是FIN/PSH/ACK,我们一般教材里面都只提到其中的FIN,是为了讲解四次挥手的原理,加以简化的。本通知的No.65报文中的ACK其实是为了响应No.64前面的数据都已经收到。PSH是要求接收端应用程序立即把数据拿走,而不是先缓存在TCP的buffer里面。
还有一点要说明的是建立连接是客户端发起的,而关闭连接,可以是客户端发起,也可以是服务端发起,本例中,就是服务器发起的。
关于状态机的分析,如下图所示。
从上图中可以看到,对于主动关闭连接的一方而言
(1)A想关闭从A到B连接,会通知TCP发送FIN包给B,然后切换状态机由Established到FIN-WAIT-1,
(2)一旦收到B的ACK报文,立即切换到FIN-WAIT-2状态,此时任然可以接收B发来的数据,
(3)当收到B发来的FIN包,要求关掉从B到A的连接时,会立马回复ACK,并进入到TIME-WAIT状态,TIME-WAIT状态的持续时间一般是2MSL,时间到了以后,会自动进入到Closed状态 。
对被动关闭连接一方而言
(1)B的TCP收到A的TCP的FIN报文后, 通知B, 并回复ACK报文A,然后切换状态机由Established到CLOSE-WAIT, 此时B可以发送数据给客户端, 但不能接收客户端的数据, 该状态持续时间长短取决于服务端给客户端数据什么时候传完,
(2)当B没有数据给A时,会通知TCP发送FIN报文,关闭此方向的连接,然后进入到LAST-ACK状态
(3)一旦收到A的ACK报文,会切换状态到Closed。
2.4 异常处理:RST报文作用
上两个小节中, 我们提到了TCP9个标志位中的SYN, ACK, FIN这三个, 除了这三个以外还有一个RST也是经常出现的.
我们知道当服务端打开端口,准备接受客户端数据时,客户端通过和服务端三次握手正常建立连接,但是如果服务端的端口没有打开,客户端强行向服务端发送SYN包,要求建立连接时,服务器怎么处理呢?
一般情况下,服务端TCP收到客户端的SYN报文, 同时发现本地的端口没有启用,服务端TCP会发送RST报文给客户端,要求连接复位。
另外当数据发送完毕后,通过四次挥手可以正常关闭连接,但是如果中途,通信任何一方出现问题,没法发送数据,该如何处置呢?
这时出现问题一方的TCP一般也会主动发送RST报文给对端,要求连接复位,这种情况出现的场景:可能是CPU、内存资源不够用、TCP缓冲区溢出、收到其他程序的关机请求等等。