一、TCP的连接建立
1、什么是面向连接
TCP属于面向连接:在发送数据之前,需要建立点到点的连接
TCP的四元组:源ip,目标ip,源端口,目标端口。可以唯一的区分和标识一条TCP的连接。
TCP和UDP的差异:
TCP:一对一;BGP(看重传输的可靠性)使用的是TCP协议
UDP:一对多;RIP,OSPF都是使用的UDP协议
连接:指的是逻辑层面的连接,本质是初始参数的约定
2、TCP的报文结构

**首部长度:**标识TCP报文头部的长度,因为存在选项字段,所以是可变长头部,最短是20个字节。
**URG:**紧急标记位,应用层定义,为1,则启用紧急指针。
**ACK:**确认标记位。为1,Acknumber=1+上一个报文的字节长度 ,则启用确认序列号字段。
**PSH:**推送标记位。为1,表示该报文不放入缓存空间,直接推送至进程。
**RST:**重置标记位。为1,表示强制断开TCP连接,不用四次挥手。
**SYN:**同步标记位。为1,表示请求建立连接,通常在三次握手的前两次用到。
FIN: 止标记位。为1,表示正常断开TCP连接,需要四次挥手。
窗口大小:进行流量控制,保障可靠性。
**校验和:**伪头部校验,校验自己的头部内容兼带数据内容,还会校验IP头部的部分字节(12个字节:32位源IP 32位目标ip 8位的保留 8位的协议号 16位的报文长度)

**序列号:**TCP是基于字节流传输的协议,这个序列号就是字节流的编号
3、TCP的三次握手
第一次握手:客户端向服务端发送请求,SYN置1,携带客户端生成seq序列号。
第二次握手:服务端向客户端回报,SYN和ACK置1,携带服务端生成的seq序列号和ack确认序列号。
第三次握手:客户端向服务端回报,携带ack确认序列号。


思考1:为什么不能使用固定的序列号?
-
保证接收端数据有序接收;
-
可以根据序号判断是否以前接收过该数据,用于去除重复;
-
判断数据的合法性;
-
序号机制结合 ACK 可以完成数据重传。
思考2:为什么序列号不从0开始?
防止黑客知道序列号后伪造数据包制造攻击
4、TCP的建立状态
客户端:
- 关闭状态:在发送SYN请求建立连接之后,进入到下一个状态;
- SYN_SENT:等待服务器返回的SYN-ACK报文,收到后进入下一个状态;
- 建立完成状态:此时客户端指向服务器的会话已经建立,所以客户端发送给服务器的最后一个ACK报文是允许携带数据的。
服务器:
- 关闭状态:当服务器应用创建一个监听的套接字之后,将进入下一个状态;
- 侦听状态:当接收到客户端发送的SYN报文之后,为TCP连接分配缓存空间,同时发送SYN-ACK报文,进入到下一个状态;
- SYN_RCVD:等待客户端返回的ACK报文,收到后进入下一个状态;
- 建立完成状态:TCP双向会话均建立完成。
在第一次握手时,若服务器没有开启listen侦听,在收到SYN报文时,会将回复报文的RST位置1,拒绝建立连接。
5、SYN泛洪攻击

SYN泛洪攻击属于DOS攻击的一种,攻击者通过伪造大量的源IP地址,向服务器发送大量的SYN包,分配缓存空间,而服务器回复SYN-ACK报文后,由于源 IP 虚假无法收到 ACK 包,致使连接资源被半开放连接占满,从而无法给正常用户提供服务。
防御方式:
①:防火墙代理
防火墙代理服务,并设置每目标IP代理阈值和每目标IP丢弃阈值。一开始,客户端正常访问服务器,达到代理阈值后,防火墙开始代理服务;达到丢弃阈值后,防火墙直接把数据包丢弃。
②:SYNcookie
服务器在收到SYN数据包后不会分配缓存空间,而是将(四元组+一个随机数)提取出来做一个hash运算,将生成的摘要值(SYNcookie)作为序列号回复给客户端,同时保存摘要值+1的数值,在进行一次hash,检验结果是否与客户端返回的Ack报文是否一致。
6、TCP建立连接为什么必须是三次握手(为什么不是四次或者两次)
三次握手相较于四次握手节省资源资源。
三次握手相较于二次握手,能够解决新旧连接造成资源混乱的问题。


二、TCP的断开连接
1、四次挥手
客户端和服务器都能主动断开连接,这里以客户端作为示例。

- 当数据快发送完时,客户端发起FIN报文时,将最后一点数据合并在FIN包中;
- 服务器回复ACK报文时,断开的是客户端指向服务器的单方面会话,此时,客户端不能给服务器发送数据,而服务器可以继续发送剩下的数据;
- 等待服务器将数据全部发送完后,再继续发送FIN报文,该报文也可以携带最后一段数据;
- 客户端回复ACK报文后,双方连接彻底断开。