当前位置: 首页 > news >正文

windows下的套接字IO模型

一般情况下,IO操作的行为受两种因素的影响:

  • IO操作对象的类型(阻塞还是非阻塞)
  • 获取IO操作结果的方式(同步还是异步).

同步就是指操作的发起和操作结果的获取由调用者完成.

异步指操作发起由调用方完成,操作结果由服务方主动告知.

IO操作一般可以分为4种:

  • 同步阻塞IO :调用方调用IO函数,并阻塞在这个函数上面.
  • 同步非阻塞IO:调用方不断的调用IO函数,直到有”明确”的返回值.
  • 异步阻塞IO:调用方发起IO操作后,阻塞在接收IO通知的API上.
  • 异步非阻塞IO:调用方发起IO操作后继续其他工作,由内核负责回调或者发出IO通知信号.

 

CJ1

阻塞IO对象在调用期间会阻塞IO函数,函数返回的时候,操作结果是明确的,因此不需要配合其他API来获取改操作的结果.

非阻塞IO对象在发生IO调用的时候,总是立即返回(返回的IO请求的结果,不是IO的执行结果),但执行结果不能马上得知,调用者可能需要使用配套的一系列API来获取IO结果(在什么时机,什么地点使用由调用方自己决定).


现在我们将IO对象放在套接字上,那么套接字有阻塞型套接字(Bolocking Socket)和非阻塞型套接字.再将目光放在windows操作系统上:

windows下套接字模型可以分为:

  • Blocking Mode               阻塞型
  • Non-blocking Mode    非阻塞型

windows下套接字IO模型:

  • The blocking Model                
  • The select Model                        
  • The WSAAsyncSelect Model
  • The WSAEventSelect Model
  • The Overlapped Model
  • The Completion Port Model

备注:

  • 上面六种基本上可以认为:按照从上到下的顺序,上面的使用最简单程度,依次递减,性能依次递增.
  • 只要调用WSAEventSelect 或者WSAAsyncSelect, 套接字都会被自动设置为Non-Blocking.
  • windows下典型的套接字API就是WSAXxxx家族函数,比如WSASend,WSARecv.因为WSAXxxx能够处理所有传统套接字API(如send,recv)的所有功能,我们只讨论前者.

Windwos下的WSAXxxx系列函数被设计成一套适合各种场景的API,看上去它非常的”聪明”,根据不同的场景有不同的语义:

  1. 如果操作的对象是一个阻塞型套接字,那么它的行为就跟传统的套接字API一样,调用方被阻塞在这个API上,直到IO操作返回结果.这种方式的最大好处是处理流程简单.
  2. 如果操作的对象是一个非阻塞套接字,它会立即返回结果(一般是WSAEWOULDBLOCK),这种方式的好处就是可以很方便的控制IO超时.

    WSAEWOULDBLOCK其实算不上一种严重的错误,在不同场景有不同的语义:

     

    Function Name

    Description

    WSAAccept and accept

    The application has not received a connection request. Call again to check for a connection.

    closesocket

    In most cases, this means that setsockopt was called with the SO_LINGER option and a nonzero timeout was set.

    WSAConnect and connect

    The connection is initiated. Call again to check for completion.

    WSARecv, recv, WSARecvFrom, and recvfrom

    No data has been received. Check again later.

    WSASend, send, WSASendTo, and sendto

    No buffer space available for outgoing data. Try again later.

  3. 当操作的对象是一个重叠IO的套接字,情况就稍微复杂一些了,以WSASend为例子,先看其函数原型:
       1: int WSASend(
       2:   __in          SOCKET s,
       3:   __in          LPWSABUF lpBuffers,
       4:   __in          DWORD dwBufferCount,
       5:   __out         LPDWORD lpNumberOfBytesSent,
       6:   __in          DWORD dwFlags,
       7:   __in          LPWSAOVERLAPPED lpOverlapped,
       8:   __in          LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
       9: );
    在发起IO操作时,lpOverlapped->hEvent 和lpCompletionRoutine 的有效性组合关系可有下面几种:
    A. lpCompletionRoutine 有效, hEvent 会被忽略.内核会在IO事件完成时调用该回调函数(lpCompletionRoutine ).
    B.lpCompletionRoutine 为NULL, hEvent 有效,内核会在IO事件完成时为这个 hEvent 设置信号.应用层可以用WSAWaitForMultipleEvents等方式等待信号.
    C. lpCompletionRoutine 和lpOverlapped都为NULL( hEvent 自然也是无效的),则视为非重叠IO套接字对待.

如果套接字句柄已经绑定到某个完成端口句柄上,回调函数必须设置为NULL,否则将得到10022(参数错误).如果IO结构体中的hEvent有效,内核仍然会为这个句柄设置信号.

重叠IO套接字上的操作通常都会立即返回,如果该操作可以立即完成则会返回字节数,否则返回(WSA_IO_PENDING),表示操作结果不能立即取得,从这个时候开始一直到完成事件到达,提交给内核的内存缓冲区将被锁定,调用方需要保证这期间该内存一直有效.因为在这种模式下,内核的策略是IO传输的数据直接缓冲到调用方的这块内存地址是,而不是套接字自身的缓冲区.这就为实现一个零拷贝(Zero Copy)的IO框架提供了可能性,试想一下,整个过程中不需要任何的memcpy,是不是很诱人?

此外,服务器也可能是一个CPU密集型服务,这个时候只需要改变一下套接字API(WSASend/WSARecv)的用法,很容易就从proactor模式切换为reactor模式,窍门就是使用零缓冲WSASend/WSARecv.

 

最后,一个常用的流程图:

CJ2

图中的FIOBNIO=TRUE表示套接字设置是非阻塞,反之为阻塞套接字.

文章信息

作者:J.Cheen

出处:www.cnblogs.com/cheen

相关文章:

  • 第一周考试总结
  • ExtJs中组件最好少使用ID属性(推荐更多使用Name属性)
  • 读书笔记-《JavaScript高级程序设计(第3版)》
  • ASP.NET MVC Model验证(一)
  • OpenCV+python轮廓
  • Objective-C语法之NSSet和NSMutableSet
  • 孤独与寂寞
  • 人工智能火了,为啥医疗成为最先受益者?
  • Java反射机制简单了解_Reflection
  • 前端 图表
  • Linux系统备份与还原
  • 如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (一)
  • java 获取HttpRequest Header 的几种方法 请求request的所有参数实现方法
  • SolrCould 集群搭建
  • 学习设计模式--观察者模式(C++)
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • Lucene解析 - 基本概念
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • nginx 负载服务器优化
  • node和express搭建代理服务器(源码)
  • passportjs 源码分析
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • SpiderData 2019年2月13日 DApp数据排行榜
  • vagrant 添加本地 box 安装 laravel homestead
  • 分类模型——Logistics Regression
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 用Python写一份独特的元宵节祝福
  • 正则表达式
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • # 计算机视觉入门
  • #HarmonyOS:Web组件的使用
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (C语言)字符分类函数
  • (Note)C++中的继承方式
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (三) diretfbrc详解
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • .htaccess配置重写url引擎
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .Net Core缓存组件(MemoryCache)源码解析
  • .NET/C# 的字符串暂存池
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • @Autowired多个相同类型bean装配问题
  • @selector(..)警告提示
  • @德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?
  • [20150629]简单的加密连接.txt
  • [Android]Android开发入门之HelloWorld
  • [BZOJ 2142]礼物(扩展Lucas定理)