三次握手与四次挥手

运输连接有三个阶段:连接建立、数据传送、连接释放
TCP在链接建立的过程中要解决三个问题
1)要使双方都能够确知对方的存在
2)要允许双方协商一些参数(如最大窗口值,是否使用窗口扩大选项和时间戳选项以及服务质量等)
3)能够对运输实体资源(如缓存大小、连接表中的项目等)进行分配
主动发起连接建立的应用进程叫做客户、而被动等待连接建立的应用进程叫做服务器
这里写图片描述
服务端状态转化:
[CLOSED -> LISTEN] 服务器端调用listen后进入LISTEN状态, 等待客户端连接;
[LISTEN -> SYN_RCVD] 一旦监听到连接请求(同步报文段), 就将该连接放入内核等待队列中, 并向客户端发送SYN确认报文.
[SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文, 就进⼊入ESTABLISHED状态,可以进行读写数据了.
[ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接(调⽤用close), 服务器会收到结束报文段,服务器返回确认报文段并进入CLOSE_WAIT;
[CLOSE_WAIT -> LAST_ACK] 进⼊入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进⼊入LAST_ACK状态,
等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
[LAST_ACK -> CLOSED] 服务器收到了对FIN的ACK, 彻底关闭连接.
客户端状态转化:
[CLOSED -> SYN_SENT] 客户端调用connect, 发送同步报文段;
[SYN_SENT -> ESTABLISHED] connect调用成功, 则进入ESTABLISHED状态, 开始读写数据;
[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close时, 向服务器发送结束报文段, 同时进入FIN_WAIT_1;
[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报⽂文段, 进⼊入TIME_WAIT, 并发出LAST_ACK;
[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间,才会进⼊入CLOSED状态.

一、TCP连接的建立(机制:“我要与你建立连接”,“好的,那我们建立连接吧 ”,“好的”)

  • TCP连接建立的过程
    第一次握手:客户端主动发起连接请求,向服务器端发送连接请求报文SYN,此时SYN=1(表示请求连接),且在此期间,可以发送一个序号seq=x(但是不能携带任何数据,但是仍然要消耗一个序号 ),此时,客户端就进入SYN_SENT状态(同步已发送状态),(此时服务器端一直处于监听状态,监听底层是否有连接请求)
    第二次握手:服务器端收到来自客户端的连接请求,如果同意连接,此时向客户端发送确认报文,SYN=1,ACK=1(表示同意连接),此时,确认号为ack=x+1。同时也为自己选择一个初始序号seq=y(不能携带任何数据,但是仍然要消耗一个序号),此时服务器端就进入SYN_RCVD(同步收到)状态
    第三次握手:客户端收到了来自服务器端确认建立连接,之后, 还要给服务器端一个确切的消息,客户端也已经准备好了,确认号ack=y+1,seq=x+1,此时ACK报文段可以携带数据,如果不携带,在此时不消耗序号,此时,TCP连接已经建立,这时,客户端进入ESTABLISHED(已建立连接)的状态,当服务器端收到来自客户端的确认之后,也进入ESTABLISHED状态,此时,两者之间就可以正常的进行通信了。

  • 为什么采用三次握手,而不采用两次握手或者四次握手
    采用三次握手,当客户向服务器发送连接请求之时,由于网络的原因,而滞留了,服务器收到了这个连接请求,认为是新的连接请求,因此对客户端给出确认,而客户端的这个连接请求已经早已不存在(失效),因此不再向服务端发送确认报文,此时,服务器端认为客户端不同意刚才的请求,因此没有给出回应,因此在服务器端就会释放这个连接请求所占用的资源,从而不会导致大量的资源白白浪费。还有一种情况就是,采用三次握手,当最后一次的确认报文丢失之时,服务器端认为客户端没有准备好,也就不再维持这样一个链接请求,但是当一段时间之后,会采用RST标志位,保证客户端的重新链接,不会使得服务端充斥着大量的无效链接。
    两次握手:如果在TCP链接建立之时,采用两次握手,如果在上述的第一种情况中,服务器端收到那个延迟请求之后,以为是有效链接,因此向客户发送确认报文,但是由于采用的是两次握手, 由于这是一个无效的请求,因此客户端无法对其作出响应,而服务器端认为链接已经建立好了,便一直维护着这个连接,从而使得资源的大大浪费。还有一种情况就是,当最后一个确认报文丢失,但是由于服务器不知道其丢失,还认为其存在,一直等待着客户发送数据,从而一直维护着这个请求。因此,有的人会利用TCP的这个机制,从而一直向服务器发送SYN请求,但是并不对其发送数据,因此使得服务器端一直充斥着大量的无效链接,然而链接的维护需要资源,所有的资源都去维护这个无效链接了,当有效链接来了,由于没有资源对其进行维护,因此只能丢弃,长时间之后,可能会使得服务器崩溃。
    四次握手:会产生与两次握手相同的情况,而且不仅如此,还浪费了大量的资源,还使得服务器端充斥着大量的无效链接
    五次握手:三次握手已经可以完成的事情,采用五次握手只是为了完成与其相同的任务,在网络中,讲究的是以最小的成本完成最大的任务,因此在维护链接需要成本的基础上,三次链接就足以。

二、TCP连接的释放(机制:“我要与你分手”,“好得”,“那我也要与你分手”,“好得, 那我同意了”)
由于TCP采用全双工的工作方式,因此当释放连接是双方的事情,必须经过双方都同意之后,才能彻底的断了联系(类似于男女朋友双方分手的例子)

  • TCP连接释放的过程
    第一次挥手:当双方通信完成之后,则需要释放连接,首先客户端向服务器端发送FIN,且FIN=1,且有seq=u,表示传送的最后一个字节序号+1,这时服务器端进入FIN_WAIT1(终止等待)状态,等待来自客户端的确认。此时注意,即使FIN报文段不携带任何数据,也会消耗掉一个序号。
    第二次挥手:客户端收到连接释放报文段后即发出确认,确认号为ack=u+1,此时这个报文段自己的序号是v,等于客户端前面已传送过的数据的最后一个字节的序号+1,此时服务端进入CLOSE_WAIT(关闭状态),此时从客户到服务器端的连接以及关闭,此时的TCP连接属于半关闭状态。在此时,如果服务器端有数据发送给客户,客户端仍然要进行接收(因为服务器到客户的连接还没有关闭),此时客户端进入FIN_WAIT2的状态,等待服务端发送的连接释放的报文段
    第三次挥手:当服务端没有数据向客户端发送之时,此时就关闭这个连接,服务端发送FIN=1,现在假定服务端的序号为w(在半关闭状态服务端可能又发送了一些数据)。服务端还必须重复上次已发送过的确认序号ack=u+1。这时服务端进入LAST_ACK状态,等待客户端的确认。
    第四次挥手:客户收到服务器的释放报文后,对此进行确认,此时客户端进入TIME_WAIT状态,此时的连接并未完全释放,必须等待2MSL(MSL也称最大报文段寿命),之后,连接才可以释放。服务器在收到确认报文之后,就立即进入到CLOSED状态。

  • 有关TIME_WAIT状态
    TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL(maximum segmentlifetime)的时间后才能回到CLOSED状态.
    我们使用Ctrl-C终止了server, 所以server是主动关闭连接的一方, 在TIME_WAIT期间仍然不能再次监听同样的server端口;
    MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s;
    可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看MSL的值;
    服务器端为主动关闭连接的一方,因此服务端会进入TIME_WAIT的状态,此时,其需要等待2MSL的时间才能绑定一样的端口号,则对于我们来进行通信十分的不方便,服务器需要处理非常大量的客户端的连接(每个连接的生存时间可能很短, 但是每秒都有很大数量的客户端来请求).这个时候如果由服务器端主动关闭连接(比如某些客户端不活跃, 就需要被服务器端主动清理掉), 就会产生⼤大量TIME_WAIT连接.由于我们的请求量很大, 就可能导致TIME_WAIT的连接数很多, 导致服务器的端口不够⽤用, 无法处理新的连接.因此要解决这个问题,可以通过这个方式,如下所示:
    使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个socket描述符,此处表示端口号的复用。

  • 为什么要等待2MSL
    能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);
    同时也是在理论上保证最后一个报文可靠到达(假设最后一个ACK丢失, 那么服务器会再重发一个FIN. 这时虽然客户端的进程不在了, 但是TCP连接还在, 仍然可以重发LAST_ACK);
    1、为了保证客户发送的最后一个ACK报文段能够到达服务器,假设客户端到服务端的最后一个ACK丢失,,因此服务端就不能收到这个FIN+ACK的确认,因此服务端就会重新重传FIN+ACK,重新启动2MSL计时,最后使得都进入正常的CLOSED状态。如果不等待2MSL,客户端在发送完ACK之后,立马就释放连接,那么服务端就无法收到客户端再次发来的FIN+ACK报文段,因而也不会再次发送确认报文段,这样,服务端就无法进入正常步骤的CLOSED状态。
    2、防止上一节提到的已失效的报文段再次出现在本链接中,,经过2MSL可以使得本链接持续的时间内产生的所有报文段都从网络中消失,这样使得下一步的连接不会出现旧的连接的请求报文。

三、TCP的异常问题
进程终止: 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.
机器重启: 和进程终止的情况相同.
机器掉电/网线断开: 接收端认为连接还在, 一旦接收端有写入操作, 接收端发现连接已经不在了, 就会进行reset. 即使没有写入操作, TCP自己也内置了一个保活定时器, 会定期询问对方是否还在. 如果⽅方不在, 也会把连接释放.
另外, 应用层的某些协议, 也有一些这样的检测机制. 例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ,在QQ断线之后, 也会定期尝试重新连接.
四、定时器
超时重传定时器, 保活定时器, TIME_WAIT定时器
保活定时器:服务器每收到一次客户的数据,就重新设置这个保活计数器,时间的设置通常是两个小时,若两个小时没有收到客户的数据,服务器就发送一个探测报文,以后每隔75分钟发送一次,若连续发送10个探测报文端后仍为客户响应,服务器就认为客户端出了故障,接着就关闭这个连接。

有关三次握手与四次挥手的内容,大概就这么多了!!!

只有不停的奔跑,才能不停留在原地!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值