select 模型解释

2023-11-13

 

套接字模式:阻塞套接字和非阻塞套接字。或者叫同步套接字和异步套接字。

套接字模型:描述如何对套接字的I/O行为进行管理。

Winsock提供的I/O模型一共有五种:

 

select,WSAAsyncSelect,WSAEventSelect,Overlapped,Completion。今天先讲解select。

 

1:select模型择模(选型)

 

先看一下下面的这句代码:

 

阻塞socket:

 

int iResult = recv(s, buffer,1024);

 

   这是用来接收数据的,在默认的阻塞模式下的套接字里,recv会阻塞在那里,直到套接字连接上有数据可读,把数据读到buffer里后recv函数才会返回,不然就会一直阻塞在那里。

 

   在单线程的程序里出现这种情况会导致主线程(单线程程序里只有一个默认的主线程)被阻塞,这样整个程序被锁死在这里,如果永远没数据发送过来,那么程序就会被永远锁死。这个问题可以用多线程解决,但是在有多个套接字连接的情况下,这不是一个好的选择,扩展性很差。

 

非阻塞 socket:

 

再看代码:

int iResult = ioctlsocket(s, FIOBIO, (unsigned long *)&ul);

iResult = recv(s, buffer,1024);

 

//-------------------------

// Initialize Winsock

WSADATA wsaData;

int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);

if (iResult != NO_ERROR)

   printf("Error at WSAStartup()/n");

 

//-------------------------

// Create a SOCKET object.

SOCKET m_socket;

m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (m_socket == INVALID_SOCKET) {

   printf("Error at socket(): %ld/n", WSAGetLastError());

   WSACleanup();

  return;

}

 

//-------------------------

// Set the socket I/O mode: In this case FIONBIO

// enables or disables the blocking mode for the

// socket based on the numerical value of iMode.

// If iMode = 0, blocking is enabled;

// If iMode != 0, non-blocking mode is enabled.

int iMode = 0;

ioctlsocket(m_socket, FIONBIO, (u_long FAR*) &iMode);

 

 

 

 

这一次recv的调用不管套接字连接上有没有数据可以接收都会马上返回。原因就在于我们用ioctlsocket把套接字设置为非阻塞模式了。不过你跟踪一下就会发现,在没有数据的情况下,recv确实是马上返回了,但是也返回了一个错误:WSAEWOULDBLOCK,意思就是请求的操作没有成功完成。 看到这里很多人可能会说,那么就重复调用recv并检查返回值,直到成功为止,但是这样做效率很成问题,开销太大。

 

 

多线程来解决使用阻塞套接字存在的问题:

 

多线程来解决阻塞套接字的方法是为阻塞套接字的IO操作创建单独的线程,阻塞的套接字IO操作放在单独的线程中,而不会因为套接字IO操作的阻塞造成整个主线程的阻塞,但是这样也会造成一定的问题:

 

1) 如果是多个套接字的场合通过多线程来解决主线程阻塞就会显得不合适了,server端创建一个监听socket来负责监听连接,而为accept函数

 

   为每个client端连接创建一个套接字,这样就会创建很多的套接字。如果是创建不同的套接字则应该创建多个线程,而每个线程的线程函数是

 

   不同的,这样就造成了所谓的扩展性很差。

 

2)如果不是每个连接创建一个套接字的话,duoxanch方法比较直观,程序非常简单而且可移植性好,但是不能利用平台相关的特性。例如,如果连接数增多的时候(成千上万的连接),那么线程数成倍增长,操作 系统忙于频繁的线程间切换,而且大部分线程在其生命周期内都是处于非活动状态的,这大大浪费了系统的资源。所以,如果你已经知道你的代码只会运行在 Windows平台上,建议采用Winsock I/O模型。

 

 

微软提供了select函数来解决这个问题:

 

int select(

int nfds,

fd_set FAR *readfds,

fd_set FAR *writefds,

fd_set FAR *exceptfds,

const struct timeval FAR *timeout

);

 

第一个参数不要管,会被系统忽略的。第二个参数是用来检查套接字可读性,也就说检查套接字上是否有数据可读,同样,第三个参数用来检查数据是否可以发出。最后一个是检查是否有带外数据可读取。

 

 

 

最后一个参数是用来设置select等待多久的,是个结构:

struct timeval {

long tv_sec; // seconds

long tv_usec; // and microseconds

};

如果将这个结构设置为(0,0),那么select函数会马上返回。

 

说了这么久,select的作用到底是什么?

 

他的作用就是:

 

1)防止在在阻塞模式的套接字里被锁死

 

2)避免在非阻塞套接字里重复检查WSAEWOULDBLOCK错误。

 

 

他的工作流程如下:

 

1:用FD_ZERO宏来初始化我们感兴趣的fd_set,也就是select函数的第二三四个参数。

2:用FD_SET宏来将套接字句柄分配给相应的fd_set。

3:调用select函数。

4:用FD_ISSET对套接字句柄进行检查,如果我们所关注的那个套接字句柄仍然在开始分配的那个fd_set里,那么说明马上可以进行相应的IO操作。比如一个分配给select第一个参数的套接字句柄在select返回后仍然在select第一个参数的fd_set里,那么说明当前数据已经来了, 马上可以读取成功而不会被阻塞。

 

 

1 #include "stdafx.h"

2 #include <iostream>

3 #include <winsock2.h>

4 #include <windows.h>

5

6 #define TRACE ATLTrace //必须要加上这个宏定义,否则在WIN32的控制台程序中是不能直接用的

7

8 #define InternetAddr "127.0.0.1"

9 #define iPort 5055

10

11 #pragma comment(lib, "ws2_32.lib")

12

13 int _tmain(int argc, _TCHAR* argv[])

14 {

15      WSADATA wsa;

16      WORD wVersionRequested;

17     int err;

18

19     wVersionRequested = MAKEWORD( 2, 2 );

20      err = WSAStartup( wVersionRequested, &wsa);

21     if ( err != 0 ) {

22     //Tell the user that we could not find a usable

23     //WinSock DLL.    

24      TRACE("你忘记添加WinSock DLL了/n");

25      WSACleanup();

26     return 1;

27       }

28

29    // Create a SOCKET for listening for   incoming connection requests

30      SOCKET fdServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

31   

32      sockaddr_in server;

33

34  server.sin_family = AF_INET;

35  server.sin_addr.s_addr = inet_addr(InternetAddr);

36  server.sin_port = htons(iPort);

37 //Bind the socket.

38     int ret = bind(fdServer, (sockaddr*)&server, sizeof(server));

39      ret = listen(fdServer, 4);

40

41      SOCKET AcceptSocket;

42      fd_set      fdread;

43  timeval     tv;

44  int nSize;

45    //其实也算是轮训,那么对阻塞socket用select和对使用非阻塞socket的优点在哪?

46   //可能的优点就是避免在非阻塞套接字里重复检查WSAEWOULDBLOCK错误。

47     while(1)

48  {

49                   

50           FD_ZERO(&fdread);//初始化fd_set

51           FD_SET(fdServer, &fdread);//分配套接字句柄到相应的fd_set

52                               

53          tv.tv_sec = 2;//这里我们打算让select等待两秒后返回,避免被锁死,也避免马上返回

54          tv.tv_usec = 0;

55                                                   

56          select(0, &fdread, NULL, NULL, &tv);

57                                                           

58          nSize = sizeof(server);

59         //先判断fdServer是否还在fd_set内来判断是否可以读,这样就避免因为 accept在等待

60         //时造成的阻塞

61         if (FD_ISSET(fdServer, &fdread))

62             //如果套接字句柄还在fd_set里,说明客户端已经有connect的请求发过来了,

63             //马上可以accept成功

64           {

65               AcceptSocket = accept(fdServer,( sockaddr*) &server, &nSize);

66              break;

67             }                                              

68         else

69         //还没有客户端的connect请求,我们可以去做别的事,避免像没有用select方式

70         //的阻塞套接字程序被锁死的情况,如果没用select,当程序运行到accept的时候客户

71         //端恰好没有connect请求,那么程序就会被锁死,做不了任何事情

72              {

73             //do something

74                 MessageBox(NULL, "waiting", "recv", MB_ICONINFORMATION);

75         //别的事做完后,继续去检查是否有客户端连接请求

76              }

77   }

78

79   char buffer[128];

80        ZeroMemory(buffer, 128);

81

82           ret = recv(AcceptSocket,buffer,128,0);//这里同样可以用select,用法和上面一样

83

84           MessageBox(NULL, buffer, "recv", MB_ICONINFORMATION);

85

86          closesocket(AcceptSocket);

87          WSACleanup();

88         return 0;

89 }

90

 

select函数的返回值 :

 

函数失败的返回值:调用失败返回SOCKET_ERROR,超时返回0。

 

 

int ret;

        if((ret=select(0,&fdread,NULL,NULL,NULL))==SOCKET_ERROR)

         {

            //Error Condition

         }

        if(ret > 0)//ret>0这个ret值表示满足条件的socket的数量,不止一个socket满足IO操作的条件

         {

            if(FD_ISSET(fdServer,&fdread))

             {

                //A read event has occured on socket fdServer

             }

         }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

select 模型解释 的相关文章

  • 从 ostream 获取 char* 而不进行复制

    我有一个ostream并且数据已写入其中 现在我想要该数据的形式char大批 有没有办法在不复制所有字节的情况下获取字符缓冲区及其大小 我的意思是 我知道我可以使用ostringstream并打电话str c str 但会产生一个临时副本
  • Log4Net 中 AdoNetAppender 中的缓冲区的惰性评估

    我正在使用 Log4Net 自定义属性将一些环境信息添加到我的日志中 我创建了一个具有全局可访问属性的实用程序类 我的程序类使用它来存储上下文信息 订单 id 用户 id 等 以及围绕它们的惰性包装器 因此我不需要一直更改 Log4Net
  • 加载生成的纹理数据在 Libgdx/Lwjgl 中是不确定的

    数据格式如下 final int width 256 final int height 256 final float data new float width height 4 FloatBuffer dataBuf int textur
  • 如何在 Vim 中打开之前打开的缓冲区?

    如何在 Vim 中打开之前打开的缓冲区 我有 4 个缓冲区 例如 buf1 到 buf4 目前我已经打开 buf1 然后打开 buf3 执行 b3 现在 如何返回 buf1 之前打开的缓冲区 而不执行 b1 Ctrl P will go t
  • python pyaudio 使用多处理

    我正在尝试从音频流中获取样本并将它们放入共享队列中 我有另一个进程从该队列中提取 当我运行时 我收到此错误 recording Traceback most recent call last File record py line 43 i
  • 是什么让某些东西成为 ASP.NET Core 中的请求功能?

    ASP NET Core 有一点我相信我还没有完全理解 那就是请求功能的想法 正如中所解释的the docs https docs asp net en latest fundamentals request features html 功
  • 如何在C#中有效地在桌面上绘图?

    我想用C 直接在桌面上画图 经过一番搜索 我最终使用了桌面 HDC 中的 Graphics 对象 空 然后 我使用这个 Graphics 对象正常绘画 问题是 当屏幕的任何部分被重绘时 我的形状就会丢失 我尝试了一个 While 循环 但它
  • 如果 CGImageCreate 的数据提供者使用应用程序创建的数组,那么正确的调用会是什么样子?

    我试图在内存中创建一个位图 作为 drawLayer inContext 方法 此方法是 CALayer 委托协议的一部分 将调用的模式函数的一部分 模式函数看起来与此类似 static const size t kComponentsPe
  • 服务器显示文本而不是 HTML

    我正在尝试创建一个 C 服务器 它将接受输入并能够通过 html 格式将它们返回给用户 其中服务器充当用户界面 我当前的问题似乎无法弄清楚为什么 C 服务器在 localhost 3838 处将 HTML 代码以文本形式吐出 而不是将其显示
  • Node.js 的 python 子脚本在完成时输出,而不是实时输出

    我是node js 和socket io 的新手 我正在尝试编写一个小型服务器 它将根据python 输出更新网页 最终这将用于温度传感器 所以现在我有一个虚拟脚本 它每隔几秒打印一次温度值 恒温器 py import random tim
  • 何时使用字节数组&何时使用字节缓冲区?

    字节数组和字节缓冲区有什么区别 另外 在什么情况下应该优先选择其中之一 我的用例是用 java 开发的 Web 应用程序 实际上有多种处理字节的方法 我同意 选择最好的并不总是那么容易 the byte the java nio ByteB
  • kivy:可以使用缓冲区作为图像源吗?

    我有如下代码 它可以从一些现有图像中生成新图像 from PIL import Image as pyImage def create compound image back image path fore image path fore
  • 在 JavaScript 或 Node 中将 Blob 数据转换为原始缓冲区

    我正在使用插件jsPDF https github com MrRio jsPDF它生成 PDF 并将其保存到本地文件系统 现在在 jsPDF js 中 有一些代码可以生成 blob 格式的 pdf 数据 如下所示 var blob new
  • 将响应缓冲区转换为 JSON

    在 AWS 中 我使用 https 模块通过 Lambda 发出 get 请求 我能够返回数据 但当我调用时它是缓冲区格式的callback null obj https get options res gt res on data d g
  • Node.js 中的缓冲区是什么?

    正如您可以在有关 Buffer 类的 Node js 文档 http nodejs org api buffer html 一个缓冲区 类似于整数数组 但对应于 V8 堆外部的原始内存分配 到目前为止 一切都很好 现在让我困惑的是 从技术上
  • 当 URL 可在浏览器中访问时,SSH Curl 不起作用

    This post is linked with another post of mine still unsolved Laravel 作曲家更新 连接被拒绝 https stackoverflow com questions 52404
  • jinja2.exceptions.TemplateNotFound:index.html

    我尝试使用 Flask 打开 index html run py from app import app app run debug True init py from flask import Flask app Flask name f
  • 如何通过pthreads管理两个或多个消费者?

    我有一个正在寻求解决的通用问题 即从标准输入或常规文件流发送到应用程序的二进制数据块 应用程序又将二进制数据转换为文本 使用线程 我想在将文本传输到下一个应用程序之前对其进行处理 该应用程序会进一步修改该文本 依此类推 作为一个简单的测试用
  • 如何使用 BufferedReader 对象从 Java 中的一行读取多个整数值?

    我正在使用 BufferedReader 类读取 Java 程序中的输入 我想读取用户的输入 该用户可以在带空格的单行中输入多个整数数据 我想读取整数数组中的所有这些数据 输入格式 用户首先输入他 她想要输入的数字数量 然后在下一行中使用多
  • IIS 如何识别请求的是哪个站点?

    如果我在一台服务器上托管多个站点 并且 dns 服务器将不同的域名解析到同一地址 这是服务器的名称 那么 IIS 如何知道最终请求的是哪个站点 因此 客户端输入我的 1 站点地址 gt myrandomsite mydomain com 然

随机推荐

  • 阿里P8大神讲解——Java,JVM内存模型

    在Java程序界流行着一种默认的说法叫 黄金5年 也就是一个程序员从入职的时间开始算起 前五年的选择直接影响着整个职业生涯发展方向和薪资走向 如何走好这5年很关键 如何彻底从一个菜鸟蜕变成 可以以不变应万变的职业大牛 这是一个涉及到自身专业
  • 朋友去华为面试,轻松拿到26K的Offer,羡慕了......

    最近有朋友去华为面试 面试前后进行了20天左右 包含4轮电话面试 1轮笔试 1轮主管视频面试 1轮hr视频面试 据他所说 80 的人都会栽在第一轮面试 要不是他面试前做足准备 估计都坚持不完后面几轮面试 其实 第一轮的电话面试除了一些常规的
  • 【电气专业知识问答】问:在何种事故情况下应立即停用电动机?

    电气专业知识问答 问 在何种事故情况下应立即停用电动机 答 1 发生危急人身安全情况 需要立即停用电动机的 2 电动机所带机械设备损坏至危险程度时 3 电动机起火冒烟 4 电动机强烈振动 窜轴或内部发生定 转子碰擦 5 电动机缺相运行 6
  • C#读写各类文件合集

    C 文件操作合集 一 利用字节流与文件流读写txt json文件 1 以文件的方式进行操作 2 以文件流的方式进行读写 3 以二进制数据流的方式进行读写 4 以文本流的方式进行读写 5 JOSN文件的读写 二 kernel32读写ini文件
  • 【论文笔记】疯狂的检测工具 —— 静态分析工具

    本文目标 精度论文 CryptoGuard High Precision Detection of Cryptographic Vulnerabilities in Massive sized Java Projects 主要针对大规模的
  • 【Pytorch Lighting】第 9 章:部署和评分模型

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • Win10系统安装使用H3C HCL实验室(最新版)方法

    如果安装了wsl2虚拟机的 首先参照此教程将wsl版本降为1 https blog csdn net qq 26123545 article details 120169070 spm 1001 2014 3001 5501 如果之前的HC
  • CMake编译.dll并使用开源库SDE

    目录 环境 项目修改 编译 dll文件并确保它能正常使用 测试使用 dll文件 文件下载链接 环境 本篇博客所要做的是 Win10环境使用CMake编译一个开源C 库 这个库所有 h头文件和 cpp源文件都有了 将这个库编译为动态链接库 d
  • armbian安装图形桌面_Linux桌面环境(桌面系统)大比拼「附带优缺点」

    早期的 Linux 系统都是不带界面的 只能通过命令来管理 比如运行程序 编辑文档 删除文件等 所以 要想熟练使用 Linux 就必须记忆很多命令 后来随着 Windows 的普及 计算机界面变得越来越漂亮 点点鼠标就能完成很多工作 人们已
  • x86-64 汇编基础 ---- 记读 《CS: APP》

    x86 64 汇编基础 记读 CS APP 通常情况下 使用现代的优化编译器产生的代码至少与一个熟练的汇编语言程序员手工编写的代码一样有效 1 看懂汇编码 1 汇编码的格式 ATT格式 这是GCC OBJDUMP和其它一些工具的常用格式 由
  • 推荐系统实战2——EasyRec 推荐框架环境配置

    推荐系统实战2 EasyRec 推荐框架环境配置 学习前言 先验条件 EasyRec仓库地址 EasyRec环境配置 一 EasyRec的下载 二 EasyRec的初始化 三 EasyRec的安装 四 一些额外的情况 学习前言 EasyRe
  • opencv 读取NV12格式(.yuv)文件,并转为RGB格式保存为JPG

    实测代码如下 include
  • OpenStack的搭建与使用

    初次接触open stack与Linux 如有错误与可改进的地方 恳请指出 一 搭建 一 配置推荐 系统 镜像 内存 储存 Linux centos7 6 16G 100G 二 前期准备 1 开启虚拟化 图2 1 开启虚拟化 2 关闭防火墙
  • C语言典型例题四——斐波那契数列

    Fibonacci 斐波那契 数列 求斐波那契数列的前40个数 这个数列有个特点 第1 2两个数为1 1 从第三个数开始 该数是其前面两个数之合 即该数列为1 1 2 3 5 8 13 这是一个有趣的古典数学问题 有一对兔子 从出生后第三个
  • python 在Excel中新增一列

    1 在Excel中定义新列 定义新列需要用到columns tolist 函数 具体代码如下 col name df columns tolist col name insert 新列位置 新列名称 wb df reindex column
  • Log4j2源码分析系列:(一)配置加载

    在实际开发项目中 日志永远是一个绕不开的话题 本系列文章试图以slf4j和log4j2日志体系为例 从源码角度分析日志工作原理 学习日志框架 首先要熟悉各类日志框架 这里推荐两篇文章 就不再赘述了 https www cnblogs com
  • C——选择结构

    选择结构 1 关系运算与逻辑运算 1 1 关系运算 1 2 逻辑运算 2 if语句 2 1 单分支的if语句 2 2 双分支的if语句 3 条件运算符 4 switch语句 1 关系运算与逻辑运算 C语言中的逻辑值 C语言将 非0 值当做值
  • buuCTF [ISITDTU 2019]EasyPHP 1

    buuCTF ISITDTU 2019 EasyPHP 1 直接代码审计 第一个if 过preg match 一般有三种方法 取反绕过 异或绕过 转义绕过 这里用取反绕过 第二个if的意思是输入的字符串不重复的字符长度不超过0xd即13 如
  • select 模型解释

    套接字模式 阻塞套接字和非阻塞套接字 或者叫同步套接字和异步套接字 套接字模型 描述如何对套接字的I O行为进行管理 Winsock提供的I O模型一共有五种 select WSAAsyncSelect WSAEventSelect Ove
  • mybatis plus分页total=0、不计算总数的终极解决方案!!!

    当你在加入分页配置 如下 Configuration public class MybatisPlusConfig mybatis plus分页插件 Bean public PaginationInterceptor paginationI