• 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。

  • 相关阅读:
    iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片
    iOS开发——多线程篇——GCD
    iOS开发——多线程篇——NSThread
    iOS开发——多线程篇——多线程介绍
    iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果
    推荐系统_七月算法4月机器学习班第9次课程笔记
    STL源码分析读书笔记--第三章--迭代器(iterator)概念与traits编程技法
    C语言基础(不断更新)
    字节对齐总结
    大端模式与小端模式
  • 原文地址:https://www.cnblogs.com/wangfengju/p/6172567.html
Copyright © 2020-2023  润新知