zoukankan      html  css  js  c++  java
  • UNIX网络编程——SOCKET API和TCP STATE的对应关系_三次握手_四次挥手及TCP延迟确认

    在socket系统调用中,如何完成三次握手和四次挥手:

         SOCK_DGRAM即UDP中的connect操作知识在内核中注册对方机器的IP和PORT信息,并没有建立连接的过程,即没有发包,close也不发包)。

         而SOCK_STREAM对应如下:

         connect会完成TCP的三次握手,客户端调用connect后,由内核中的TCP协议完成TCP的三次握手;

         close操作会完成四次挥手。

     

    三次握手对应的Berkeley Socket API:

         可以看出和连接建立相关的API有:connect, listen,accept   3个,connect用在客户端,另外2个用在服务端。

         对于TCP/IP protocol stack来说,TCP层的tcp_in&tcp_out也参与这个过程。我们这里只讨论这3个应用层的API干了什么事情。

    (1) connect

         发送了一个SYN,收到Server的SYN+ACK后,代表连接完成发送最后一个ACK是protocol stack,tcp_out完成的

    (2)listen

         在server这端,准备了一个未完成的连接队列,保存只收到SYN_C的socket结构;

         准备了已完成的连接队列,即保存了收到了最后一个ACK的socket结构。

    (3)accept

         应用进程调用accept的时候,就是去检查上面说的已完成的连接队列,如果已完成的队列里有连接,就返回这个连接;如果没有,即空的,blocking方试调用,就睡眠等待;nonblocking方式调用,就直接返回,一般一"EWOULDBLOCK“ errno告诉调用者,连接队列是空的。 


     注意:

            在上面的socket API和TCP STATE的对应关系中,TCP协议中,客户端收到Server响应时,可能会有会延迟确认。

            即客户端收到数据后,会阻塞给Server端确认。

            可以在每次收到数据后:

                   调用setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){1}, sizeof(int));  快速给Server端确认。

                        

     

     

    我们如何判断有一个建立连接请求一个关闭连接请求

          建立连接请求:

    1、connect将完成三次握手,accept所监听的fd上,产生读事件,表示有新的连接请求;           

    关闭连接请求:

    1、close将完成四次挥手,如果有一方关闭sockfd,对方将感知到有读事件,

          如果read读取数据时,返回0,即读取到0个数据,表示有断开连接请求。(在操作系统中已经这么定义

        

     

      

    关闭连接过程中的TCP状态和SOCKET处理,及可能出现的问题:


        TIME_WAIT

      TIME_WAIT 是主动关闭 TCP 连接的那一方出现的状态,系统会在 TIME_WAIT 状态下等待 2MSL(maximum segment lifetime  )后才能释放连接(端口)。通常约合 4 分钟以内。

    进入 TIME_WAIT 状态等待 2MSL 的目的:

              1、确保连接可靠地关闭; 即防止最后一个ACK丢失

              2、避免产生套接字混淆(同一个端口对应多个套接字)

     意思是,一方close发送了关闭连接请求,对方的应答迟迟到不了(例如网络原因),导致TIME_WAIT超时,此时这个端口又可用了,我们在这个端口上又建立了另外一个socket连接。如果此时对方的应答到了,怎么处理呢?其实这个在TCP层已经处理了,由于有TCP序列号,所以内核TCP层,就会将包丢掉,并给对方发包,让对方将sockfd关闭。 所以应用层是没有关系的。即我们用socket API编写程序,就不用处理。

    注意:

    TIME_WAIT是指操作系统的定时器会等2MSL,而主动关闭sockfd的一方,并不会阻塞。(即应用程序在close时,并不会阻塞)。

    当主动方关闭sockfd后,对方可能不知道这个事件。那么当对方(被动方)写数据,即send时,将会产生错误,即errno为: ECONNRESET。

    服务器产生大量 TIME_WAIT 的原因:(一般我们不这样开发Server)

    服务器存在大量的主动关闭操作,需关注程序何时会执行主动关闭(如批量清理长期空闲的套接字等操作)。

     一般我们自己写的服务器进行主动断开连接的不多,除非做了空闲超时之类的管理。(TCP短连接是指,客户端发送请求给服务器,客户端收到服务器端的响应后,关闭连接)。


    CLOSE_WAIT

    CLOSE_WAIT 是被动关闭 TCP 连接时产生的如果收到另一端关闭连接的请求后,本地(Server端)不关闭相应套接字就会导致本地套接字进入这一状态

    (如果对方关闭了,没有收到关闭连接请求,就是下面的不正常情况)

     

    按状态机,我方收到FIN,则由TCP实现发送ACK,因此进入CLOSE_WAIT状态。但如果我方不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接

     

    如果存在大量的 CLOSE_WAIT,则说明客户端并发量大,且服务器未能正常感知客户端的退出,也并未及时 close 这些套接字。(如果不及时处理,将会出现没有可用的socket描述符的问题,产生问题的原因,没有及时close)。

     

    正常情况下,一方关闭sockfd,外一方将会有读事件产生, 当recv数据时,如果返回值为0,表示对端已经关闭。此时我们应该调用close,将对应的sockfd也关闭掉

     

    不正常情况下,一方关闭sockfd,另外一方并不知道,(比如在close时,自己断网了,对方就收不到发送的数据包)。此时,如果另外一方再向对应的sockfd上写send或读recv数据。

    recv时,将会返回0,表示连接已经断开。

    send时, 将会产生错误,errno为ECONNRESET。

  • 相关阅读:
    wex5 实战 框架拓展之2 事件派发与data刷新
    wex5 实战 框架拓展之1 公共data组件(Data)
    wex5 实战 HeidiSQL 导入Excel数据
    wex5 实战 手指触屏插件 hammer的集成与优劣
    wex5 实战 登陆帐号更换与用户id一致性
    wex5 实战 用户点评与提交设计技巧
    wex5 实战 省市县三级联动与地址薄同步
    wex5 实战 wex5与js的组件关系与执行顺序(父子与先后)
    wex5 实战 单页模式下的多页面数据同步
    [BZOJ]4237: 稻草人
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6332586.html
Copyright © 2011-2022 走看看