模拟select通信过程

文章目录

      • 模拟select通信过程
    • 但有客户端正在处理数据,新增一台客户端请求建立连接
    • 当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接,请分析它的过程
    • 当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接, 并且连接后立即发送数据 ,请分析它的过程
    • 复杂一点的模拟
      • 为什么不能同时处理 A的数据和B C的数据
      • 总结

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>int main()
{// 1. 创建监听的fdint lfd = socket(AF_INET, SOCK_STREAM, 0);// 2. 绑定struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = INADDR_ANY;bind(lfd, (struct sockaddr*)&addr, sizeof(addr));// 3. 设置监听listen(lfd, 128);// 将监听的fd的状态检测委托给内核检测int maxfd = lfd;// 初始化检测的读集合fd_set rdset;fd_set rdtemp;// 清零FD_ZERO(&rdset);// 将监听的lfd设置到检测的读集合中FD_SET(lfd, &rdset);// 通过select委托内核检测读集合中的文件描述符状态, 检测read缓冲区有没有数据// 如果有数据, select解除阻塞返回// 应该让内核持续检测

上面的代码不在分析范围之内

while(1){// 默认阻塞// rdset 中是委托内核检测的所有的文件描述符rdtemp = rdset;int num = select(maxfd+1, &rdtemp, NULL, NULL, NULL);   //--------------- A// rdset中的数据被内核改写了, 只保留了发生变化的文件描述的标志位上的1, 没变化的改为0// 只要rdset中的fd对应的标志位为1 -> 缓冲区有数据了// 判断// 有没有新连接if(FD_ISSET(lfd, &rdtemp))    // -----------------B {// 接受连接请求, 这个调用不阻塞struct sockaddr_in cliaddr;int cliLen = sizeof(cliaddr);int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &cliLen); // ---------------- C// 得到了有效的文件描述符// 通信的文件描述符添加到读集合// 在下一轮select检测的时候, 就能得到缓冲区的状态FD_SET(cfd, &rdset);        // ----------------D// 重置最大的文件描述符maxfd = cfd > maxfd ? cfd : maxfd;  // --------- E}// 没有新连接, 通信for(int i=0; i<maxfd+1; ++i){// 判断从监听的文件描述符之后到maxfd这个范围内的文件描述符是否读缓冲区有数据if(i != lfd && FD_ISSET(i, &rdtemp))    // ------------ F {// 接收数据char buf[10] = {0};// 一次只能接收10个字节, 客户端一次发送100个字节// 一次是接收不完的, 文件描述符对应的读缓冲区中还有数据// 下一轮select检测的时候, 内核还会标记这个文件描述符缓冲区有数据 -> 再读一次// 	循环会一直持续, 知道缓冲区数据被读完位置int len = read(i, buf, sizeof(buf)); if(len == 0)                 // ---------------------- G {printf("客户端关闭了连接...\n");// 将检测的文件描述符从读集合中删除FD_CLR(i, &rdset);  //------------------------------ H close(i);}else if(len > 0){// 收到了数据// 发送数据write(i, buf, strlen(buf)+1);}else{// 异常perror("read");}}}}

模拟select通信过程

假设现在有N个客户端

如果客户端都只建立连接,而不传输数据 的情况.

程序运行到 A 处 时, select 会 判断 监听描述符(lfd) 和 通信描述符(cfd) 的 读 缓冲区是否有数据,

若有数据 则将对应文件描述符 的 读缓冲区 有数据的文件描述符 置为 1

由于客户端不进行传输数据, 只会请求建立连接, 故只有 监听描述符(lfd ) 的读缓冲区设为1.(实际上客户端的写缓冲区也有数据,但我们并不关心客户端的写缓冲区,select 也没有 检查 写缓冲区的数据)

继续运行到 B 处时 由于 lfd 读缓冲区有数据 ,FD_ISSET(lfd, &rdtemp) 为真, 故执行if 语句内容,

继续运行到 C 处时, accpet 返回一个 和 服务端进行连接的 cfd ,但仍然需要检查这个cfd 的读缓冲区时候有数据, 故将其加入读集合,等待下次select 进行检测读缓冲区. 此时程序运行到D 处.

继续运行到 E 处, 将我们得到的 cfd 和 maxfd 比较大小 (更新maxfd), 这个 maxfd 是 在 select 内部起作用的, select 会 循环遍历 文件描述符,符 判断文件描述符的读缓冲区 ,maxlfd 用于 限制 遍历的上 界.

程序运行到 F 处时 会检测 监听描述符 (cfd) 的读缓冲区, 由于客户端 不传输数据 ,所以直接进入下一次while 循环.

但有客户端正在处理数据,新增一台客户端请求建立连接

假设前 N -1 台客户端 处于连接 但 不 传输数据的 状态 , 第 N 台客户端由于在F 处检测到读缓冲区有数据, 此时正在传输数据. 此时 第 N+1 台客户端 请求建立连接. 第 N+1 台客户端并不会阻塞等待第 N 台 客户端完成数据传输( read 函数不是还在读取第N台客户端的数据吗?? ), 而是成功建立连接. 原因如下:

这涉及到网络编程中的并发处理和非阻塞I/O。在我的例子中,服务器使用了select()函数来同时处理多个网络连接。这就是所谓的I/O多路复用技术。

  1. 并发处理:服务器可以同时处理多个客户端的连接请求,而不是顺序地一个接一个地处理。这是通过创建一个文件描述符集合(在你的例子中是rdset),并使用select()函数来检测这些文件描述符的状态变化(例如,是否有新的连接请求,或者已连接的客户端是否有可读的数据)。
  2. 非阻塞I/O:当服务器调用select()函数时,如果没有任何文件描述符的状态变化,那么这个函数会阻塞,直到有状态变化发生。然而,一旦有文件描述符的状态变化(例如,有新的连接请求),select()函数就会立即返回,而不会等待其他文件描述符(例如,正在传输数据的客户端)。这就意味着服务器不会因为一个客户端正在传输数据而阻塞等待。

因此,即使第N台客户端正在传输数据,第N+1台客户端也可以发送连接请求,并且服务器可以接受这个请求,而不会阻塞等待第N台客户端完成数据传输。

在我的假设中,前N-1台客户端已经连接但不传输数据,第N台客户端正在传输数据。当第N+1台客户端请求建立连接时,这是会发生的:

  1. A处,select()函数会阻塞并等待任何文件描述符(包括监听文件描述符和已连接的客户端文件描述符)的状态变化。这包括新的连接请求和已连接的客户端有可读的数据。
  2. 当第N+1台客户端发出连接请求时,监听文件描述符(在这个例子中是lfd)的状态会变化。因此,select()函数会返回,并且FD_ISSET(lfd, &rdtemp)B处将会为真。
  3. C处,服务器会接受第N+1台客户端的连接请求。这将创建一个新的文件描述符(我们可以称之为cfdN+1)来与第N+1台客户端通信。
  4. D处,新的文件描述符cfdN+1会被添加到读集合(rdset)中,以便在下一轮select()检测时能够得知其状态。
  5. E处,如果新的文件描述符cfdN+1大于当前的最大文件描述符(maxfd),那么它将成为新的最大文件描述符。

因此,即使前N台客户端已经连接并且第N台客户端正在传输数据,服务器仍然可以接受第N+1台客户端的新连接请求。

当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接,请分析它的过程

当N台服务器都处于通信状态,其中有一台由于客户端断开而处在G处时,如果它立即重新请求连接,以下是可能的过程:

  1. G处,服务器检测到客户端已经断开连接,因此它会关闭与该客户端的连接(使用close(i)),并从文件描述符集合中移除该文件描述符(使用FD_CLR(i, &rdset))。
  2. 如果客户端立即重新请求连接,监听文件描述符(在这个例子中是lfd)的状态会变化。因此,select()函数会返回,并且FD_ISSET(lfd, &rdtemp)B处将会为真。
  3. C处,服务器会接受客户端的新连接请求。这将创建一个新的文件描述符(我们可以称之为cfdNew)来与客户端通信。
  4. D处,新的文件描述符cfdNew会被添加到读集合(rdset)中,以便在下一轮select()检测时能够得知其状态。
  5. E处,如果新的文件描述符cfdNew大于当前的最大文件描述符(maxfd),那么它将成为新的最大文件描述符。

因此,即使有一台服务器由于客户端断开而处在G处,只要客户端立即重新请求连接,服务器就可以立即接受这个新的连接请求。

服务器使用了select()函数来同时处理多个网络连接,这就是所谓的I/O多路复用技术。这意味着服务器可以同时处理多个客户端的连接请求和数据传输,而不是顺序地一个接一个地处理,客户端不会等待其他客户端通信完,才会被受理.

当N台服务器都处于通信状态,其中有一台由于客户端断开处在G处,如果它立即重新请求连接, 并且连接后立即发送数据 ,请分析它的过程

当N台服务器都处于通信状态,其中有一台由于客户端断开而处在G处时,如果它立即重新请求连接,并且连接后立即发送数据,以下是可能的过程:

  1. G处,服务器检测到客户端已经断开连接,因此它会关闭与该客户端的连接(使用close(i)),并从文件描述符集合中移除该文件描述符(使用FD_CLR(i, &rdset))。
  2. 如果客户端立即重新请求连接,监听文件描述符(在这个例子中是lfd)的状态会变化。因此,select()函数会返回,并且FD_ISSET(lfd, &rdtemp)B处将会为真。
  3. C处,服务器会接受客户端的新连接请求。这将创建一个新的文件描述符(我们可以称之为cfdNew)来与客户端通信。
  4. D处,新的文件描述符cfdNew会被添加到读集合(rdset)中,以便在下一轮select()检测时能够得知其状态。
  5. E处,如果新的文件描述符cfdNew大于当前的最大文件描述符(maxfd),那么它将成为新的最大文件描述符。
  6. 如果客户端在连接后立即发送数据,那么在下一轮的 select() 检测时,由于 cfdNew 的状态发生了变化(有数据可读), select() 函数会返回,并且 FD_ISSET(cfdNew, &rdtemp)F 处将会为真。
  7. F 处,服务器会读取客户端发送的数据,并处理这些数据。

因此,即使有一台服务器由于客户端断开而处在 G 处,只要客户端立即重新请求连接并发送数据,服务器就可以接受这个新的连接请求并处理这些数据。希望这个解释能帮助你理解!

复杂一点的模拟

假设我们有四个客户端(A、B、C和D)和一个使用select()函数的服务器。

  1. 初始状态:所有客户端都已连接到服务器,服务器正在监听所有客户端的文件描述符。
  2. 客户端A发送数据:客户端A发送一些数据。select()函数检测到客户端A的文件描述符状态变化,返回并处理这些数据。
  3. 客户端B和C同时发送数据:在服务器处理客户端A的数据时,客户端B和C同时发送数据。由于select()函数可以同时处理多个文件描述符的状态变化,所以它会在处理完客户端A的数据后立即返回,并开始处理客户端B和C的数据。
  4. 客户端D请求连接:在服务器处理客户端B和C的数据时,客户端D发送连接请求。select()函数检测到监听文件描述符的状态变化,返回并接受客户端D的连接请求。
  5. 客户端A断开连接:在服务器接受客户端D的连接请求后,客户端A断开连接。服务器检测到这个状态变化,关闭与客户端A的连接,并从文件描述符集合中移除该文件描述符。
  6. 客户端D发送数据:最后,客户端D发送一些数据。服务器检测到这个状态变化,返回并处理这些数据。

为什么不能同时处理 A的数据和B C的数据

在使用select()函数的服务器中,虽然select()函数可以同时监控多个文件描述符的状态变化,但是处理这些状态变化(例如接受新的连接请求,读取或写入数据)的代码是在一个单线程中顺序执行的。

这就意味着,如果一个操作(例如读取大量数据或执行计算密集型任务)需要花费很长时间,那么这个线程将会被占用,直到这个操作完成。在此期间,服务器无法处理其他操作(例如接受新的连接请求),因为它们都在同一个线程中。

即使在这个期间有新的连接请求到来,select()函数也无法被调用,因为它在等待当前的操作完成。所以说,其他的操作必须等待。

这就是为什么我们说,在使用select()函数实现的服务器中,并不是所有的操作都是并发执行的。对于需要处理大量并发连接或执行复杂操作的应用程序,可能需要使用其他技术(例如多线程、多进程或异步I/O)。

总结

select()函数是一种I/O多路复用技术,它的主要特点和作用如下:

  1. 并发处理select()函数可以同时处理多个网络连接。它通过创建一个文件描述符集合,并检测这些文件描述符的状态变化(例如,是否有新的连接请求,或者已连接的客户端是否有可读的数据)。
  2. 非阻塞I/O:当服务器调用select()函数时,如果没有任何文件描述符的状态变化,那么这个函数会阻塞,直到有状态变化发生。然而,一旦有文件描述符的状态变化(例如,有新的连接请求),select()函数就会立即返回,而不会等待其他文件描述符(例如,正在传输数据的客户端)。这就意味着服务器不会因为一个客户端正在传输数据而阻塞等待。
  3. 文件描述符限制select()函数使用一个位图来表示文件描述符集合,位图的大小通常由操作系统限制(通常为1024)。这意味着select()函数只能同时监控有限数量的文件描述符。
  4. 效率问题:每次调用select()函数时,都需要遍历整个文件描述符集合来检查哪些文件描述符的状态发生了变化。当文件描述符数量很大时,这将导致效率问题。

因此,虽然select()函数实现的TCP服务器端代码可以同时处理多个网络连接,但它并不是完全并发的。对于需要处理大量并发连接或执行复杂操作的应用程序,可能需要使用其他技术(例如,多线程、多进程或异步I/O)。希望这个总结能帮助你理解!

这意味着select()函数只能同时监控有限数量的文件描述符。
4. 效率问题:每次调用select()函数时,都需要遍历整个文件描述符集合来检查哪些文件描述符的状态发生了变化。当文件描述符数量很大时,这将导致效率问题。

因此,虽然select()函数实现的TCP服务器端代码可以同时处理多个网络连接,但它并不是完全并发的。对于需要处理大量并发连接或执行复杂操作的应用程序,可能需要使用其他技术(例如,多线程、多进程或异步I/O)。希望这个总结能帮助你理解!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全中的渗透测试主要有几个方面

渗透测试中主要有软件测试和渗透测试。 1、测试对象不同   软件测试&#xff1a;主要测试的是程序、数据、文档。 渗透测试&#xff1a;对象主要为网络设备、主机操作系统、数据库系统和应用系统。 2、测试内容不同   软件测试&#xff1a;主要工作内容是验证和确认&#x…

如何将word格式的文档转换成markdown格式的文档

如何将word格式的文档转换成markdown格式的文档 前言 A. 介绍Markdown和Word格式文档 什么是Markdown&#xff1f; Markdown是一种轻量级标记语言&#xff0c;旨在简化文本格式化和排版的过程。它以纯文本形式编写&#xff0c;通过使用简单的标记语法&#xff0c;使文档更具…

使用Objective-C和ASIHTTPRequest库进行Douban电影分析

概述 Douban是一个提供图书、音乐、电影等文化内容的社交网站&#xff0c;它的电影频道包含了大量的电影信息和用户评价。本文将介绍如何使用Objective-C语言和ASIHTTPRequest库进行Douban电影分析&#xff0c;包括如何获取电影数据、如何解析JSON格式的数据、如何使用代理IP技…

学习Python的NumPy、pandas、matplotlib笔记

关于Numpy、Pandas、matplotlib笔记 关于Numpy的学习Numpy的代码练习 关于Pandas的学习Pandas代码的练习 关于Matplotlib的学习Matplotlib代码练习 关于Numpy的学习 Numpy的代码练习 import numpy as np anp.array([[1,2],[3,4]]) print(a) print(a.dtype) a.astype(np.float1…

响应式设计疑难问题全解析!一篇读懂,立即上手

在我们当前的技术环境中&#xff0c;响应式设计已经成为前端开发的重要部分。其目标是让网站能够以最优的方式在任何设备上工作——不论是大屏电脑、笔记本、平板还是智能手机。这就要求网页能够自适应不同设备的屏幕大小。下面就让我们深入浅出地探讨响应式设计的精髓&#xf…

AI:50-基于深度学习的柑橘类水果分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

Qt 使用QtXlsx操作Excel表

1.环境搭建 QtXlsx是一个用于读写Microsoft Excel文件&#xff08;.xlsx&#xff09;的Qt库。它提供了一组简单易用的API&#xff0c;可以方便地处理电子表格数据。 Github下载&#xff1a;GitHub - dbzhang800/QtXlsxWriter: .xlsx file reader and writer for Qt5 官方文档…

虚拟机防火墙关闭教程

虚拟机防火墙关闭教程 连接数据库请求超时 教程

主机ping、ssh连接不通本地虚拟机

一、问题描述 在使用vscode remote ssh时&#xff0c;连接timeout&#xff0c;而且主机无论如何也ping不通虚拟机&#xff0c;但是虚拟机可以ping通主机。通过vagrant也可以连接虚拟机。 二、解决方案 试了网上包括设置remote ssh在内的许多方法都不行。重新查看主机和虚拟机…

15种稳定扩散模型的技术示例

推荐Stable Diffusion自动纹理工具&#xff1a; DreamTexture.js自动纹理化开发包 什么是稳定扩散模型&#xff1f; 潜在扩散模型 &#xff08;LDM&#xff09; 是一种图像生成技术&#xff0c;其工作原理是在潜在表示空间中迭代“去噪”数据&#xff0c;然后将表示解码为完整…

自己动手实现一个深度学习算法——二、神经网络的实现

文章目录 1. 神经网络概述1&#xff09;表示2&#xff09;激活函数3&#xff09;sigmoid函数4&#xff09;阶跃函数的实现5&#xff09;sigmoid函数的实现6)sigmoid函数和阶跃函数的比较7&#xff09;非线性函数8&#xff09;ReLU函数 2.三层神经网络的实现1&#xff09;结构2&…

设置防火墙

1.RHEL7中的防火墙类型 防火墙只能同时使用一张,firewall底层调用的还是lptables的服务: firewalld:默认 &#xff0c;基于不同的区域做规则 iptables: RHEL6使用&#xff0c;基于链表 Ip6tables Ebtables 2.防火墙的配置方式 查看防火墙状态: rootlinuxidc -]#systemct…

建议没用过这个的社区人都来试试!

不是吧&#xff0c;还有社区工作者不知道这个好东西嘛&#xff1f; 就是这个——写作火火&#xff0c;是写报告、方案一把好手啊 直接输入想写的内容&#xff0c;几秒钟报名啊方案啊就来了&#xff0c;不满意可以重新写&#xff0c;直到你满意为止&#xff0c;真的很方便。 …

[一] C++入门

摘要&#xff1a;OOP(面向对象)&#xff0c;namespace&#xff0c;cout and cin&#xff0c;缺省参数&#xff0c;函数重载&#xff0c;引用&#xff0c;内联函数&#xff0c;auto&#xff0c;范围 for&#xff0c;nullptr 20世纪80年代&#xff0c;计算机界提出了OOP(object o…

Hadoop RPC简介

数新网络-让每个人享受数据的价值https://www.datacyber.com/ 前 言 RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用协议&#xff0c;一种通过网络从远程计算机上请求服务&#xff0c;而不需要了解底层网络技术的协议。RPC它假定某些协议的存在&#xff0c;例…

【计算机网络】计算机网络中的基本概念

文章目录 局域网LAN基于网线直连基于集线器组建基于交换机组建基于交换机和路由器组建 广域网WANIP地址端口号协议为什么要有协议知名协议的默认端口 五元组协议分层TCP/IP五层模型封装和分用 网络互连就是将多台计算机连接在一起&#xff0c;完成数据共享。数据共享本质是网络…

查询平均提速 700%,奇安信基于 Apache Doris 升级日志安全分析系统

本文导读&#xff1a; 数智时代的到来使网络安全成为了不可忽视的重要领域。奇安信作为一家领先的网络安全解决方案领军者&#xff0c;致力于为企业提供先进全面的网络安全保护&#xff0c;其日志分析系统在网络安全中发挥着关键作用&#xff0c;通过对运行日志数据的深入分析…

正则表达式续篇

位置锚定&#xff1a; ^:行首锚定&#xff0c;表示以什么为开头 例如&#xff1a; $:行尾锚定&#xff0c;表示以什么为结尾 例如&#xff1a; ^&#xff1a;匹配的是空行 例如&#xff1a; ^root$&#xff1a;匹配整行&#xff0c;而且整行只能有这一个字符串 实验&#x…

Java 集成阿里Kafka

配置文件 kafka-config:bootstrap-servers: server-url #写自己的地址sasl-username: ********sasl-password: ********ssl-truststore: src/main/resources/only.4096.client.truststore.jks## sasl路径&#xff0c;demo中有&#xff0c;请拷贝到自己的某个目录下&#xff0c…