Python资源共享群:626017123
0x00 前言
本文先介绍因特网的核心协议 TCP ,再以 Python 的 socket 模块为例介绍网络套接字,最后给出 TCP 服务器与客户端的 Python 脚本,并演示两者之间的通信过程。
0x01 TCP 协议
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接、可靠的、基于字节流的传输层通信协议。
TCP 协议的执行过程分为连接创建(Connection Establishment)、数据传送(Data Transfer)和连接终止(Connection Termination)三个阶段,其中「连接创建」与「连接终止」分别是耳熟能详的 TCP 协议三次握手(TCP Three-way Handshake)与四次挥手(TCP Four-way Handshake),也是理解本文 TCP 服务器与客户端通信过程的两个核心阶段。
为了能更好地理解下述过程,对 TCP 协议头的关键区段做以下几点说明:
- 报文的功能在 TCP 协议头的标记符(Flags)区段中定义,该区段位于第 104~111 比特位,共占 8 比特,每个比特位对应一种功能,置 1 代表开启,置 0 代表关闭。例如,SYN 报文的标记符为 00000010,ACK 报文的标记符为 00010000,ACK + SYN 报文的标记符为 00010010。
- 报文的序列号在 TCP 协议头的序列号(Sequence Number)区段中定义,该区段位于第 32~63 比特位,共占 32 比特。例如,在「三次握手」过程中,初始序列号 seq 由数据发送方随机生成。
- 报文的确认号在 TCP 协议头的确认号(Acknowledgement Number)区段中定义,该区段位于第 64~95 比特位,共占 32 比特。例如,在「三次握手」过程中,确认号ack 为前序接收报文的序列号加 1,代表下一次期望接收到的报文序列号。
连接创建
所谓的「三次握手」,即 TCP 服务器与客户端成功建立通信连接必经的三个步骤,共需通过三个报文完成。
一般而言,首先发送 SYN 报文的一方是客户端,服务器则是监听来自客户端的建立连接请求。
Handshake Step 1
客户端向服务器发送 SYN 报文(SYN=1)请求建立连接。
此时报文的初始序列号为 seq = x ,确认号为ack = 0,发送完毕后,客户端进入 SYN_SENT 状态。
Handshake Step 2
服务器接收到客户端的 SYN 报文后,发送 ACK + SYN 报文(ACK=1,SYN=1)确认客户端的建立连接请求,并也向其发起建立连接请求。
此时报文的序列号为 seq = y,确认号为 ack = x+1,发送完毕后,服务器进入 SYN_RCVD状态。
Handshake Step 3
客户端接收到服务器的 SYN 报文后,发送 ACK 报文(ACK=1)确认服务器的建立连接请求。
此时报文的序列号为 seq=x+1,确认号为 ack=y+1。发送完毕后,客户端进入 ESTABLISHED 状态;当服务器接收该报文后,也进入了 ESTABLISHED 状态。
至此,「三次握手」过程全部结束,TCP 通信连接成功建立。
读者可参照以下「三次握手」的示意图进行理解:
连接终止(Connection Termination)
所谓的「四次挥手」,即 TCP 服务器与客户端完全终止通信连接必经的四个步骤,共需通过四个报文完成。
由于 TCP 通信连接是全双工的,因此每个方向的连接可以单独关闭,即可视为一对「二次挥手」,或一对单工连接。主动先发送 FIN 报文的一方,意味着想要关闭到另一方的通信连接,即在此方向上不再传输数据,但仍可以接收来自另一方传输过来的数据,直到另一方也发送 FIN 报文,双方的通信连接才完全终止。
注意,首先发送 FIN 报文的一方,既可以是客户端,也可以是服务器。下面以客户端先发起关闭请求为例,对「四次挥手」的过程进行讲解。
Handshake Step 1
当客户端不再向服务器传输数据时,则向其发送 FIN 报文(FIN=1)请求关闭连接。
此时报文的初始序列号为 seq = u ,确认号为ack = 0,(若此报文中 ACK=1,则 ACK 的值与客户端的前序接收报文有关)。发送完毕后,客户端进入 FIN_WAIT_1 状态。
Handshake Step 2
服务器接