每天一个前端面试题之 TCP三次握手
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在TCP协议中,主动发起请求的一端为客户端,被动连接的一端称为服务端。不管是客户端还是服务端,TCP连接建立完成后都能发送和接收数据,所以TCP也是一个全双工的协议。
文章目录
一、TCP标志符集头字段
1.标志符
URG(urgent 紧急)
: 表示本数据包的数据部分包含紧急信息,是最高优先级数据报文,此时紧急指针有效。用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;
ACK(acknowledgement 确认)
: 表示确认号字段是否有效,0为无效,1为有效。
PSH(push 传送)
: 表示数据到达接收端后,接收端应该立即将数据push给应用层,而不是等到缓冲区满后再提交。
RST(reset 重置)
: 连接复位请求。表示当前TCP连接出现严重问题,可能需要重新建立TCP连接。也可以用于拒绝非法的报文段和拒绝连接请求。
SYN(synchronous 同步)
:表示同步序号,用来建立连接。SYN=1,ACK=0表示这是一个连接请求报文,SYN=1,ACK=1表示这是一个同意建立连接的应答报文。
FIN(finish 结束)
: 表示数据传送完成,可以释放连接。
2.部分头字段
Seq(Sequence number 序列号码)
:32位,用来标识从TCP发送端向TCP接收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号;它是随机生成的,保证了TCP传输的报文都是有效的,主要用来解决网络报乱序的问题;
Ack(Acknowledge number 确认号码)
:32位,表示上一个序号的数据已经收到,还包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
Window Size(窗⼝⼤⼩)
: 16位,表示还能接收多少字节的数据,⽤于流量控制
二、TCP连接建立的过程
起初,服务端与客户端都为CLOSED状态。在通信开放之前,双方都会创建套接字(socket)。服务器创建完套接字后进入LISTEN状态,开始等待客户端发送数据。客户端创建完套接字后准备开始发送请求
- 客户端向服务端发送链接请求报文段。同步标志位SYN=1,序列号Seq=x。请求发送后,客户端进入同步已发送SYN-SENT状态,等待服务器的确认。
- 服务端收到链接请求报文后,如果同意连接,则会发送⼀个应答,同步标志位SYN=1,确认标志位ACK=1,确认序号Ack=x+1, 序列号Seq=y。发送完成后服务端进入同步收到SYN-RCVD状态。
- 客户端收到连接同意的应答后,还要向服务端发送一个确认报文。确认标志位ACK=1,确认序号Ack=y+1,序列号Seq=x+1。客户端发送完报文后进入连接已建立阶段ESTABLISHED。服务端收到这个应答后也进⼊连接已建ESTABLISHED 状态,此时连接建⽴成功。
TCP连接建立完成后就可以进行数据传输了。
三、一些问题
1.为什么是三次握手,不是二次握手或者四次握手
这个问题的本质是信道不可靠, 但是通信双方需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的.
第一次握手,服务端知道客户端可以成功的发送数据,自己可以成功的接收数据
第二次握手,客户端知道端知道自己可以成功的发送数据也可以成功的接收数据,也知道服务端可以成功的接收数据和发送数据。至此,客户端可以确保彼此的信道可靠。但是此时,服务端还不知道自己能否成功的发送数据,客户端能否成功的接收数据。因此两次握手是不行的
第三次握手,服务端知道客户端可以成功的接收数据,也知道自己可以成功的发送数据。到此,双方都可以确认对方可以成功的发送和接收数据了,可以确保信道是可靠的了,因此没有必要进行四次握手了。
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不用的表述其实阐明的是同一个问题。
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。” 这样就防止了服务端的一直等待而浪费了资源。
2.三次握手中可以携带数据吗
第一次第二次不可以,第三次可以。
假如第一次握手可以携带数据的话,那对于服务器是不是太危险了,有人如果恶意攻击服务器,每次都在第一次握手中的SYN报文中放入大量数据。而且频繁重复发SYN报文,服务器会花费很多的时间和内存空间去接收这些报文,服务器就更容易被攻击了。
第三次握手,此时客户端已经处于ESTABLISHED状态。对于客户端来说,他已经建立起连接了,并且已经知道自身和服务器的接收和发送能力都是正常的。所以也就可以携带数据了。
3.握手失败服务端如何处理
握手失败有两种情况:
第一种发生在第一次握手的过程中,服务端没有收到同步标志位SYN,此时服务端不做任何处理。
第二种情况发生在第二次握手或第三次握手过程中,服务器回复了同步标志位SYN和确认标志位ACK,但是没有收到客户端的确认标志位ACK,则超时后服务器就会发送RST重置连接报文,释放资源。
4.如果已经建立了连接,但是客户端突然出现故障了怎么办
先说一下TCP连接管理中的保活机制。TCP通信中,设有一个计时器,服务端每收到一个客户端的请求就会重置这个计时器。若两端7200s内没有数据往来,则这时候每隔75s,服务端会向客户端发送一个保活探测数据报,要求客户端进行回复。若连续发送10次都没有收到响应,就断开连接。
所以,如果客户端突然出现了故障,服务端不会白白的等待浪费资源,他会根据保活机制进行探测,断开与客户端的连接。
5.什么是半连接队列
在第一次握手后,服务端接收到客户端发来的SYN后回复SYN和ACK,此后服务端进入同步收到SYN-RCVD阶段。在这个阶段,服务端会将收到的请求连接放入一个队列中,这个队列就叫半连接队列。
与此对应的就是全连接队列,就是已经完成三次握手,建立起来连接的就会放在全连接队列中,如果队列满了就有可能出现丢包现象。
6.ISN为什么要动态随机生成
ISN的全称是Initial Sequence Number,是对序列号Seq的初始化。TCP初始化序列号不能设置为一个固定值,因为这样容易被攻击者猜出后续序列号,从而遭到攻击。
——————————————————————
三、补充一下UDP
Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
简单来说,UDP是一个面向报文的传输协议,数据传输之前不需要建立连接。UDP只是数据报文的搬运工,不会对报文进行任何的拆分和拼接操作。
具体来说,在发送端,应用层将数据传递给传输层的UDP协议,UDP只会增加一个UDP头标识下的UDP协议,然后就传递给网络层了。在接收端,网络层将数据传递给传输层,UDP只去除IP报文头就传递给应用层了,不会进行任何的拼接操作。
UDP与TCP相比具有以下几个特点:
- 不可靠性。不建立连接,不关心对方是否正确收到数据,非拥塞,在网络不好的情况下可能会丢包。
- 高效性。UDP的头部开销小,只有8字节,对系统资源要求少,传输报文快。
- 提供一对多,多对一,多对多的传输方式。也就是单播,广播,多播。