SOCKET API和TCP STATE的对应关系__三次握手(listen,accept,connect)__四次挥手close及TCP延迟确认

本文主要是介绍SOCKET API和TCP STATE的对应关系__三次握手(listen,accept,connect)__四次挥手close及TCP延迟确认,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520118139252103/

 

SOCKET API和TCP STATE的对应关系__三次握手(listen,accept,connect)__四次挥手close及TCP延迟确认(调用一次setsockopt函数,设置TCP_QUICKACK)__长连接API小心“窜包”问题 

2011-09-13 21:08:15|  分类: Linux网络编程 |  标签: |举报 |字号 订阅

在我们学习网络基础时,传输层的协议有TCP和UDP;

在Linux网络编程中,我们使用socket API,实现网络通信。

那么:

        socket API 和 TCP 协议中各个状态是如何对应的呢?我们可以通过下图来看:

Linux网络编程socket API和TCP State的对应关系 - 无影 - 激情、专注、坚持、思考

          

在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处理,及可能出现的问题:

1. 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,但是web服务器等这种多客户端的Server,是需要在完成一次请求后,主动关闭连接的,否则可能因为句柄不够用,而造成无法提供服务。)

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

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


2. CLOSE_WAIT

CLOSE_WAIT 是被动关闭 TCP 连接时产生的

如果收到另一端关闭连接的请求后本地(Server端)不关闭相应套接字就会导致本地套接字进入这一状态

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

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

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

正常情况下::  

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

不正常情况下:: 

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

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

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


长连接API小心“串包”问题:

有时候,我们以API的方式为客户提供服务,如果此时你提供的API采用TCP长连接,而且还使用了TCP接收超时机制(API一般都会提供设置超时的接口,例如通过setsockopt设置SO_RCVTIMEO或这select),那你可能需要小心下面这种情况(这里姑且称之为“窜包”,应用程序没有将应答包与请求包正确对应起来):
      如果某一笔以TCP接收的请求超时(例如设置为3秒)返回客户,此时客户继续使用该链接发送第二个请求,此时后者就有可能收到前一笔请求的应答(前一笔的应答在3秒后才到达),倘若错误的将此应答当做后者的应答处理,那就可能会导致严重的问题。如果网络不稳定,或者后台处理较慢,超时严重,其中一笔请求应答窜包了,很可能导致后续多个请求应答窜包。例如网上常见的抽奖活动,第一个用户中了一个iPad,而第二个用户在后台中仅为一个虚拟物品,若此时出现窜包,那第二个用户也会被提示中了iPad。

SOCKET API和TCP STATE的对应关系__三次握手(listen,accept,connect)__四次挥手close及TCP延迟确认(调用一次setsockopt函数,设置TCP_QUICKACK)__长连接API小心“窜包”问题 - 无影 - 专注、坚持、思索

这个问题,初看起来最简单的解决办法就是:一旦发现有请求超时,就断开并重新建立连接,但这种方案理论上是不严谨的,考虑下面这种情况:
        1、应答超时的原因是因为应答包在网络中游荡(例如某个路由器崩溃等原因,这类在网络中游荡的包,俗称迷途的分组);
        2、API在检测到超时后,断开并重新建立的连接的IP和Port与原有连接相同(新连接为被断开连接的化身);
        3、在新连接建立后,立即发送了一个新的请求,但随后那个迷途的应答包又找到了回家的路,重新到达,此时新连接很有可能将这个不属于自己的包,当做第二个请求的应答(该包的TCP Sequence恰好是新连接期望的TCP Sequence,这种情况是可能的,但是基本不可能发生)。
       注:正常情况下,TCP通过维持TIME_WAIT状态2MSL时间,以避免因化身可能带来的问题。但是在实际应用中,我们可以通过调整系统参数,或者利用SO_LINGER选项使得close一个连接时,直接到CLOSE状态,跳过TIME_WAIT状态,又或者利用了端口重用,这样就可能会出现化身。在实际应用中,上面这种情况基本不会发生,但是从理论上来说,是可能的。

再仔细分析,就会发现这个问题表面上看是因为“窜包”导致,但本质原因是程序在应用层没有对协议包效验。例如另外一种情况:A、B两个客户端与Server端同时建立了两个连接,如果此时Server端有BUG,错将A的应答,发到B连接上,此时如果没有效验,那同样会出现A请求收到B应答的情况。所以这个问题解决之道就是:在应用层使用类似序列号这类验证机制,确保请求与应答的一一对应。

参考文章:

http://pananq.com/index.php/page/9/

 

 

 

这篇关于SOCKET API和TCP STATE的对应关系__三次握手(listen,accept,connect)__四次挥手close及TCP延迟确认的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/716678

相关文章

鸿蒙中@State的原理使用详解(HarmonyOS 5)

《鸿蒙中@State的原理使用详解(HarmonyOS5)》@State是HarmonyOSArkTS框架中用于管理组件状态的核心装饰器,其核心作用是实现数据驱动UI的响应式编程模式,本文给大家介绍... 目录一、@State在鸿蒙中是做什么的?二、@Spythontate的基本原理1. 依赖关系的收集2.

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

pytorch+torchvision+python版本对应及环境安装

《pytorch+torchvision+python版本对应及环境安装》本文主要介绍了pytorch+torchvision+python版本对应及环境安装,安装过程中需要注意Numpy版本的降级,... 目录一、版本对应二、安装命令(pip)1. 版本2. 安装全过程3. 命令相关解释参考文章一、版本对

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

python安装whl包并解决依赖关系的实现

《python安装whl包并解决依赖关系的实现》本文主要介绍了python安装whl包并解决依赖关系的实现,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录一、什么是whl文件?二、我们为什么需要使用whl文件来安装python库?三、我们应该去哪儿下