这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战
三次握手相关标志位
在上图中展示的是TCP的报文结构,而其中,和三次握手联系最为紧密的就是绿色字处的TCP Flags
- 紧急URG: 当URG=1,表明紧急指针字段有效。这时发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。需要和后面的紧急指针(Urgent Pointer)配合使用。
- 确认ACK: 当ACK=1时,确认字段才有效。当ACK=0时,确认号无效。在连接建立后所有传送的报文段都必须把ACK置1。
- 推送PSH: 接收方收到PSH=1的报文段,就尽快地(但不是立即)将收到的数据交付给接收应用进程,而不再等到整个缓存都填满了再交付。
- 复位RST: 当RST=1时,表明TCP连接中出现严重差错,比如用户关闭了浏览器,这时候服务器还给客户端发数据,就会被reset 报connect reset错误
- 同步SYN: 三次握手必备标志位。
- 终止FIN: 用来释放连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放传输连接。
这里需要注意TCP的头部是20Byte,而UDP的头部是8Byte,所以这就是为什么
三次握手详细介绍
整个流程为:
1.客户端主动打开,发送连接请求报文段,将SYN标识位置为1,顺序号(seq)置为x(TCP规定SYN=1时不能携带数据,x为随机产生的一个值),然后进入SYN_SEND状态
2.服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,顺序号(seq)置为y(注意两边的seq的起始不一定一致),ACK置为x+1(这样客户端就知道是针对我的seq为x的确认),然后进入SYN_RECV状态,这个状态被称为半连接状态
3.客户端再进行一次确认,将ACK置为1(此时不用SYN),顺序号(seq)置为x+1,ack置为y+1(意思是我收到了你顺序号为y的确认,期望可以接收到你的顺序号为y+1的数据)发向服务器,最后客户端与服务器建立连接
为什么不是两次握手
这主要是为了防止已经失效的连接请求报文段突然又传回到服务端而产生错误的场景。客户端发出连接请求,第一个发出后没有得到服务端的应答,于是就发送了第二个,受到服务端的确认,第二个建立了连接,数据传输完毕后,释放了连接。
如果网络超时时间过长,客户端发送完第一个连接请求报文段并没有按时到达,而是在连接释放之后的某个时间点才到达服务端。如果是二次握手的话,那么服务器就会认为这是一次新的连接请求,服务端会向客户端发出请求报文段,同意建立连接,如果是二次握手,那么服务端就会认为已经建立了连接了。
但是客户端会认为这个第一个是无效的,不会理会服务端的确认数据,那么服务端就一直等待客户端发送数据就浪费资源了。
采用三次握手的办法可以防止上述现象的发生。比如在上述的场景下,客户端不向服务端的发出确认请求,服务端由于收不到确认,就知道客户端并没有要求建立连接。