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

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

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

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

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

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

阻塞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.

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

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

文章信息

作者:J.Cheen

出处:www.cnblogs.com/cheen

windows下的套接字IO模型的更多相关文章

  1. (转)Linux下select, poll和epoll IO模型的详解

    Linux下select, poll和epoll IO模型的详解 原文:http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll ...

  2. 套接字IO超时设置和使用select实现超时管理

    在涉及套接字IO超时的设置上有一下3种方法: 1.调用alarm,它在指定的时期满时产生SIGALRM信号.这个方法涉及信号的处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有的alarm ...

  3. Windows下性能最好的I/O模型——完成端口

    I/O模型--完成端口 设计目的: 常见的网络通信分为两种:同步和异步. 在同步通信中,每一次接受数据都会导致主线程的挂起,从而阻塞住了其他操作.为了解决这一问题,我们通常会采取同步通信+多线程的策略 ...

  4. TCP套接字编程模型及实例

    摘要:     本文讲述了TCP套接字编程模块,包括服务器端的创建套接字.绑定.监听.接受.读/写.终止连接,客户端的创建套接字.连接.读/写.终止连接.先给出实例,进而结合代码分析. PS:本文权当 ...

  5. QT下UDP套接字通信——QUdpSocket 简单使用

    QT下UDP套接字通信--QUdpSocket QUdpSocket类提供一个UDP套接字. UDP(用户数据报协议)是一种轻量级.不可靠.面向数据报.无连接的协议.它可以在可靠性不重要的情况下使用. ...

  6. Linux下select, poll和epoll IO模型的详解

    http://blog.csdn.net/tianmohust/article/details/6677985 一).Epoll 介绍 Epoll 可是当前在 Linux 下开发大规模并发网络程序的热 ...

  7. windows和linux套接字中的select机制浅析

    先来谈谈为什么会出现select函数,也就是select是解决什么问题的? 平常使用的recv函数时阻塞的,也就是如果没有数据可读,recv就会一直阻塞在那里,这是如果有另外一个连接过来,就得一直等待 ...

  8. linux网络环境下socket套接字编程(UDP文件传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  9. Socket编程实践(9) --套接字IO超时设置方法

    引:超时设置3种方案 1. alarm超时设置方法 //代码实现: 这种方式较少用 void sigHandlerForSigAlrm(int signo) { return ; } signal(S ...

随机推荐

  1. spring 拦截器拦截点的配置

    实用正则org.springframework.aop.support.RegexpMethodPointcutAdvisor 然后 <property name="advice&qu ...

  2. C++学习总结1

    一.内存管理 一般new 与 delete 同时出现.假如释放一个对象用 delete p即可.多个对象用delet [ ]p  即:new与delete需要搭配好. C++继承了C的许多函数,mal ...

  3. C++ sort函数用法

    参考文档:http://hi.baidu.com/posinfo/item/dc3e73584c535cc9d2e10c27 C++ sort函数用法 FROM:http://hi.baidu.com ...

  4. 2.nginx整合PHP

    /usr/local/src/下都有什么:.tar.gz文件和解压之后的源码 /usr/local/下都有什么:源码编译之后的东西 安装mysql客户端 安装mysql服务端 启动mysql服务端 s ...

  5. 基于websocket实现的web聊天室

    # -*- coding:utf-8 -*- import socket import base64 import hashlib def get_headers(data): "" ...

  6. gulp css html image js 合并压缩

    安装node.js  npm  以及安装gulp等方法我就不在这里赘述了. 接下里我主要介绍的是Gulpfile文件里面的配置该如何书写. var gulp = require('gulp');//引 ...

  7. iOS菜鸟学习--怎样避免两个button同一时候响应

    在測试应用时.有时会变态的将两个UIButton同一时候按住来測试.结果就是两个button会同一时候响应,会出现同一时候push两个viewcontroller等非正常情况.为了避免用户误操作造成这 ...

  8. 设置Activity进入退出动画

    http://blog.csdn.net/tenpage/article/details/7792689 http://blog.csdn.net/lnb333666/article/details/ ...

  9. Python数据分析简介

    1,Python作为一门编程语言开发效率快,运行效率被人诟病,但是Python核心部分使用c/c++等更高效的语言来编写的还有强大的numpy, padnas, matplotlib,scipy库等应 ...

  10. echarts 饼状图

    说明:这是我做项目时自己写的小例子,里面有冗余的参数. 开发环境 vs2012 asp.net mvc4  c# 1.显示效果 2.HTML代码 <%@ Page Language=" ...