zoukankan      html  css  js  c++  java
  • 不得不学的 TCP三次握手和四次挥手

           提起TCP,它的体系太过庞大了(足以写了一套书TCP/IP详解卷一,卷二,卷三),以前只买了第一卷阅读,由于我们是码农级别的人,很难真正的研究透,就好比汽车,大大大部分人只会开,但让他弄懂发动机原理甚至做出模型来就难了,我们关注下tcp为什么要三握手四挥手,这很重要(特别是java操作数据库时印象深刻),其实其它也很重要,码农们要是有时间和精力,可以精读这套书,写写心得体会,最好是能写个案例。

           说正题,百度百科是这样解释的: TCP/IP协议,TCP提供一种“”可靠“”的“”面向连接“”的字节流传输层服务,面向连接意味着两个使用TCP的应用(通常是一个客户端和一个服务端)在彼此交换数据之前必须先建立一个·TCP连接。这一过程与现实场景的打电话相似,先拨号,等待对方接听后,才能通话。

    TCP 为提供可靠性传输,实行“顺序控制”或“重发控制”机制。此外还具备“流控制(流量控制)”、“拥塞控制”、提高网络利用率等众多功能,不同于UDP

    TCP有以下特点:

    • TCP充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制;

    • 此外,TCP 作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费;

    • 根据 TCP 的这些机制,在 IP 这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)。

    它在OSI七层协议与TCP/IP四层协议的位置如下图:

    在TCP/IP协议中,TCP处在传输层,TCP数据被封装在IP数据报中,如下图:

    TCP首部数据格式如下图:

    TCP首部:源端口、目标端口、序列号、确认序号、数据偏移、保留、控制位、窗口大小、校验和、紧急指针、选项、填充。

    控制位:8位。CWR、ECE、URG、ACK、PSH、RST、SYN、FIN

    CWR:为1 就通知对方已将拥塞窗口缩小

    ECE:为1 就通知对方这边的网络有拥塞

    URG:为1 包中有需要紧急处理的数据

    ACK(Acknowledgement):为1 确认应答的字段变为有效

    PSH(PUSH):为1 表示要将收到的数据立刻传给上层应用协议

    RST:为1 表示TCP连接出现异常必须要强制断开

    SYN(Synchronize Sequence Numbers):为1 请求建立连接

    FIN:为1 请求断开连接

    seq:序列号

    ack(注意和大写的·ACK区别):Acknowledge number确认号码

    TCP连接是通过三次握手进行初始化的。又由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式,所以需要四次挥手关闭连接。

    三次握手(Three-way Handshake)(重点):

    三次握手, 是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个报文。

    三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时, 将触发三次握手。

    三次握手过程的示意图如下:

          

    图1   三次握手建立连接

    详细说明:

    第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。

    第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。

    第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

    四次挥手(重点):

    四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发。

    由于TCP连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

    下面来看看四次挥手的流程图:

    图2  tcp四次挥手

    中断连接端可以是客户端,也可以是服务器端。

    第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。

    第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。

    第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。

    第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

    为什么连接的时候是三次握手,关闭的时候却是四次握手?

    建立连接时因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。所以建立连接只需要三次握手。

    由于TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议,TCP是全双工模式
    这就意味着,关闭连接时,当Client端发出FIN报文段时,只是表示Client端告诉Server端数据已经发送完毕了。当Server端收到FIN报文并返回ACK报文段,表示它已经知道Client端没有数据发送了,但是Server端还是可以发送数据到Client端的,所以Server很可能并不会立即关闭SOCKET,直到Server端把数据也发送完毕。
    当Server端也发送了FIN报文段时,这个时候就表示Server端也没有数据要发送了,就会告诉Client端,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

    暂时就写这么多,以后慢慢补充,TCP/IP协议族博大而精深

  • 相关阅读:
    redis参数AOF参数的bug
    tidb损坏tikv节点怎么恢复集群
    mysql主从延时临时解决办法
    python脚本批量杀死redis链接
    pt-online-schema-change 脚本化
    mysql查看锁等信息SQL
    mongo复制集脑裂问题如何处理
    日志收集及网络包收集方案
    各浏览器下载文件名不乱码的解决办法
    java 中 byte[]、File、InputStream 互相转换
  • 原文地址:https://www.cnblogs.com/dongguangming/p/12641368.html
Copyright © 2011-2022 走看看