- 确认ACK,仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1;
- 同步SYN,在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1;
- 终止FIN,用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;
-
TCP连接的建立(三次握手)
先附上TCP连接的图吧,然后拿图来分析:
1. 服务器先创建传输控制块TCB,然后服务器进入监听阶段
2.(第一次握手)客户端创建传输控制块TCB,然后发送一个请求连接SYN(SYN=1是请求连接)以及自己的序号seq,假设seq是x,发送完毕后客户端进入SYN-SENT(同步已发送)阶段
3.(第二次握手)当服务器收到客户端发送的一个连接请求后,服务器发送一个确认收到的ACK(ACK=1表示自己已经收到)已经一个确认号(期望下一次收到的序号)ack=x+1,一个请求连接SYN已经自己的一个序号seq=y
4.(第三次握手)当客户端收到服务的确认之后,给服务器发送一个确认ACK,一个确认号ack=y+1以及自己的一个序号seq=x+1
5.客户端与服务器的连接建立成功,开始数据传输
为什么TCP的连接需要建立三次握手么?不能建立两次握手呢?
有人会困惑为什么要进行三次握手呢(两次确认)?这主要是为了防止已失效的请求连接报文忽然又传送到了,从而产生错误。
假设TCP连接只是建立两次握手的话,那么当第二次握手的时候服务器给客户端传输报文的途中突然链路堵塞了,这时候客户端没有收到服务器的一个确认数据报,我们都知道TCP有一个超时重传机制,客户端会再次请求服务器发送确认数据报,当客户端收到以后会跟服务器建立连接,但是之后链路又可以通行了,客户端突然收到服务器传来的一个确认数据报,这时候他会再次建立连接,这时候就会浪费资源.
例如:
假定A向B发送一个连接请求,由于一些原因,导致A发出的连接请求在一个网络节点逗留了比较多的时间。此时A会将此连接请求作为无效处理 又重新向B发起了一次新的连接请求,B正常收到此连接请求后建立了连接,数据传输完成后释放了连接。如果此时A发出的第一次请求又到达了B,B会以为A又发起了一次连接请求,如果是两次握手:此时连接就建立了,B会一直等待A发送数据,从而白白浪费B的资源。 如果是三次握手:由于A没有发起连接请求,也就不会理会B的连接响应,B没有收到A的确认连接,就会关闭掉本次连接。
而我们说的三次握手则不会产生这种现象,仔细分析一下,如果服务器在给客户端传输确认数据报的时候链路堵塞了,重传,客户端收到后会给服务器发送一个ACK和一个确认号ack=y+1已经自己的一个seq=x+1,如果这时候收到链路堵塞时服务器传给客户端的数据报,由于确认号与预期的不一样,预期ack=x+2,堵塞ack=x+1,所以客户端不会理会这一段确认数据报,直接丢弃.这样就不会出现连接出现两次而出现资源浪费的情况.
TCP连接的释放(四次挥手)
老规矩先附上TCP连接释放的图,然后拿图来分析:
1.(第一次挥手)由客户端先发送一个FIN(FIN=1请求释放连接),以及自己的一个序号seq=u(这时候客户端已经不能向服务器端发送其他数据了)
2.(第二次挥手)当服务器收到客户端的一个关闭请求之后,会发送一个确认ACK,以及一个确认号ack=u+1和自己的序号seq=v
3.当服务器给客户端发送完确认ACK后,服务器还是能向客户端传输数据的,客户端虽然不能发送数据但是还是能接受数据的
4.(第三次挥手)当服务器把剩余的数据发送完之后,就向服务器端发送一个FIN,以及自己的一个seq=w(假设刚刚服务器端又向客户端传送了一些数据),以及一个确认号ack=u+1
5.(第四次挥手)当客户端收到服务器端发送后客户端会发送一个确认ACK,ack=w+1以及自己的一个序号u+1,客户端需要等待2MSL然后再关闭
6.当服务器收到客户端的一个确认ACK后,服务器会立马关闭,
为什么第四次挥手,服务器收到客户端的确认ACK,服务器会立马关闭而客户端为什么不是发送之后直接断开连接而会等待2MSL才关闭呢?
假设客户端在发送ACK后直接关闭,如果确认号在中途丢失,服务器没有接受到,根据TCP的确认重传机制,服务器会再次发送一个释放连接的FIN,而这时候客户端已经关闭了,那么服务器端就关闭不了了
若客户端在2MSL后关闭则不会出现这个问题,如果客户端的确认数据报在途中丢失,在2MSL内服务器会再次向客户端发送一个释放连接的FIN,客户端在收到收到这个数据报后又会重启计时器,就解决了这个问题
为什么TCP建立连接是三次握手而释放连接却是四次挥手呢?
因为TCP是全双工通信,在客户端主动发起释放连接的请求后,只能说客户端已经完成了所以的数据传输,而不再发送数据了,但是还是可以接受数据的,而服务器端发送ACK后直接关闭是不行的,因为服务器端还有可能些数据没有发送完的,所以服务器在发送确认ACK之后可能会传输剩余的数据给客户端再发送释放连接FIN。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。