一般情况下,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. 【转载】读懂IL代码就这么简单(三)完结篇

    一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认为 ...

  2. Python的专有属性

  3. GoogleFusionTablesAPI初探地图与云计算

    http://developer.51cto.com/art/200906/129324.htm http://yexiaochai.iteye.com/blog/1893735 http://yex ...

  4. 文件I/O相关函数

    open()和openat()函数: #include <fcntl.h> // 成功返回文件描述符,出错返回-1 int open(const char *path, int oflag ...

  5. ipython notebook 如何打开.ipynb文件?

    标签: pythontensorflow 2017-03-29 14:17 235人阅读 评论(0) 收藏 举报  分类: TensorFlow(13)  转自:https://www.zhihu.c ...

  6. 关于CSS和CSS3的布局小知识(干货)

    最近在网站偶然看到的这个网站,进去看了下讲的CSS布局,感觉还不错,讲易懂且实用推荐给大家. http://zh.learnlayout.com/

  7. 通过JAVA调用命令行程序

    这是我在把数据导入到数据库时遇到问题,总结下来的.包含两个方法,一个方法是读取文件路径下的文件列表,主方法是执行cmd命令,在导入时想得到导入一个文件的时间,涉及到线程阻塞问题,这个问题理解不是很深, ...

  8. 图像处理之滤波---gabor

    http://blog.csdn.net/xiaowei_cqu/article/details/24745945 小魏北大

  9. 多线程(C++)临界区Critical Sections

    一 .Critical Sections(功能与Mutex相同,保证某一时刻只有一个线程能够访问共享资源,但是不是内核对象,所以访问速度比Mutex快,但是没有等待超时的功能,所以有可能导致死锁,使用 ...

  10. 导入EXCEL 时间数据为小数 问题

    同事在做将EXCEL导入数据库功能时发现一个奇怪的问题:在EXCEL中,有一列数据明明呈现出时间格式,比如:18:35,但导到数据库中,居然一串长长的小数:0.7743055555555556,我靠, ...