1. 窗口
TCP使用窗口机制进行流量控制
1.1. 什么是窗口?
连接建立时, 各端分配一块缓冲区用来存储接收的数据, 并将缓冲区的尺寸发送给另一端
接收方发送的确认信息中包含了自己剩余的缓冲区尺寸
剩余缓冲区空间的数量叫做窗口
2. TCP的流控过程

3. TCP连接
建立TCP连接需要三次握手, 而断开连接则需要四次挥手.
位码即tcp标志位, 有6种标示:
- SYN synchronous, 建立联机
- ACK acknowledgement, 确认
- PSH push, 传送
- FIN finish, 结束
- RST reset, 重置
- URG urgent, 紧急
其他参数:
- Sequence number 顺序号码)
- Acknowledge number 确认号码)
整个过程如下:

3.1. 3次握手
TCP 在传输上是双工传输, 不区分 Client 端与 Server 端, 为了便于理解, 我们把主动发起建连请求的一端称作 Client 端, 把被动建立链接的一端称作 Server 端.
首先建立链接前需要 Server 端先监听端口, 因此 Server 端建立链接前的初始状态就是 LISTEN 状态
- Client 发送 SYN 请求, 进入
SYN_SENT状态. - Server 收到后, 发送 SYN+ACK 应答, 进入
SYN_RECV状态. - Client收到后, 发送ACK应答, 双方进入
ESTABLISHED状态.双方成功建立连接, 开始传输数据.
三次握手是为了建立双向的链接
3.2. 4次挥手
- Client发送FIN请求, 进入
FIN_WAIT_1状态. - Server收到后, 发送ACK应答, 进入
CLOSE_WAIT状态;Client收到后, 进入FIN_WAIT_2状态. - Server在完成数据传输后, 发送FIN请求, 进入
LAST_ACK状态. - Client收到后, 发送ACK应答, 进入
TIME_WAIT状态, 等待一段时间后关闭连接;服务端收到后, 进入CLOSED状态, 关闭连接.请求结束.
客户端TCP状态变化:
SYN_SEND -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED
服务端TCP状态变化:
LISTEN -> SYN_RECV -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED
各个状态的意义如下:
LISTEN - 侦听来自远方TCP端口的连接请求
SYN-SENT -在发送连接请求后等待匹配的连接请求
SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认
ESTABLISHED- 代表一个打开的连接, 数据可以传送给用户
FIN-WAIT-1 - 等待远程TCP的连接中断请求, 或先前的连接中断请求的确认
FIN-WAIT-2 - 从远程TCP等待连接中断请求
CLOSE-WAIT - 等待从本地用户发来的连接中断请求
CLOSING -等待远程TCP对连接中断的确认
LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认
TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认
CLOSED - 没有任何连接状态
3.3. 为什么建立连接是3次握手, 而关闭连接却是4次挥手?
建立连接时, 服务器端在收到SYN请求后, 会把SYN+ACK放在一个报文里发给客户端.
而关闭连接时, FIN表示发送方已经完成数据传输, 但仍能接收数据;接收方在传输完所有数据后, 需要再次发起一个FIN表示同意关闭连接.
因此, FIN和ACK一般分开发送.
3.4. 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
考虑到网络的不稳定性.假设最后一个ACK对方没有收到, 那么对方在超时后将重发FIN, 主动关闭端接收到重发的FIN后可以再次发送ACK应答.
4. SYN攻击
在三次握手过程中, Server发送SYN-ACK之后, 收到Client的ACK之前的TCP连接称为半连接(half-open connect), 此时Server处于SYN_RCVD状态, 当收到ACK后, Server转入ESTABLISHED状态.SYN攻击就是Client在短时间内伪造大量不存在的IP地址, 并向Server不断地发送SYN包, Server回复确认包, 并等待Client的确认, 由于源地址是不存在的, 因此, Server需要不断重发直至超时, 这些伪造的SYN包将产时间占用未连接队列, 导致正常的SYN请求因为队列满而被丢弃, 从而引起网络堵塞甚至系统瘫痪.SYN攻击时一种典型的DDOS攻击, 检测SYN攻击的方式非常简单, 即当Server上有大量半连接状态且源IP地址是随机的, 则可以断定遭到SYN攻击了, 使用如下命令可以让之现行:
1 | netstat -nap | grep SYN_RECV |
5. 如何解决 TCP 粘包问题
- 使用定长的packet
- 使用特定的分隔符
- 在消息头声明消息长度