看我之前的文章就知道,一般对于网络读的socket,都会加上O_NONBLOCK,非阻塞的选项。

int setnonblocking(int fd) {
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}

为什么要加上呢。是为了效率。下面详细说一下阻塞和非阻塞。

基本概念:

阻塞IO: 必须做完IO操作才会返回。

非阻塞IO:操作成功与否,都会返回,需要通过其他方式判断具体操作是否成功。

阻塞与非阻塞的区别:没有数据到达的时候,是否立刻返回。

读(read, recv, msgrcv):

注意,这里的读,只是负责把数据从底层系统缓存copy到我们指定的位置。实际的数据到达是系统做的。

阻塞情况(read, recv, msgrcv的行为):

1. 如果没有数据,会一直等待;

2. 有数据时候会读到用户指定的缓存区,但是如果数据量比较少,少于参数指定的大小,read也会立即返回,而不会一直等到数据足够。

阻塞读的原则:数据不超过指定长度的时候,有多少读多少,没有数据就会一直等待。

所以一般情况下,都需要采用循环读的方式,因为一次read不能保证读完需要的全部数据。

非阻塞情况(read, recv, msgrcv的行为)

1. 没有数据,就立即返回;

2. 有数据,也是采用有多少读多少的方式来处理。

所以,read完一次,要判断读到的数据长度或者错误码再决定是否再次读取。注意这里的EAGAIN错误码是需要继续读取,而返回0是对方已关闭连接。

对非阻塞socket而言,EAGAIN不是一种错误。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。错误信息为Resource temporarily unavailable,errno代码为11(EAGAIN)。

如果出现EINTR即errno为4,错误描述Interrupted system call,操作也应该继续。

EINTR指操作被中断唤醒,需要重新读/写。
而EAGAGIN不需要重新读/写已经操作的数据。 最后,如果recv的返回值为0,那表明连接已经断开,我们的接收操作也应该结束。

综上,对于读而言,阻塞与非阻塞的区别在于,没有数据到达的时候是否立刻返回。

而recv函数有一个 MSG_WAITALL的参数。

recv(sockfd, buff, buff_size, MSG_WAITALL);

这个参数意味着recv会争取等到数据填满buff_size再返回,但是如果有中断的情况, recv还是会被大端,造成没有读完buff_size的长度。

所以即使采用了recv+MSG_WAITALL的方式,还是要循环读取,当然在大多数情况下是能读满的。

注意:MSG_WAITALL只能在阻塞模式下使用,和非阻塞模式不能同时使用。

写(write/send/msgsnd)的本质也是把用户态数据copy到系统底层去,然后由系统进行发送和实际写操作。只要完成了copy,就意味着写完成。

阻塞情况(write/send/msgsnd的行为)

与阻塞读有多少读多少不同的是,阻塞写会一直阻塞,直到所有数据都完成,再返回。

这是因为,读的时候不知道需要读多少,防止一直等不到足够的数据;而写的时候是知道要写多少数据的。不过也可能被中断,大多数情况是能够写完的。

非阻塞情况(write/send/msgsnd的行为)

非阻塞写,就是有多少写多少。能够写多少是根据本地网络拥塞情况为标准的,当网络拥塞严重的时候,网络层没有足够的内存来进行写操作,就会出现写不完的情况;这时候,阻塞写除非被中断,都会等到数据都写完;而非阻塞写,就是能写多少算多少。

IO模式设置方式

Socket:

方法1: 文章开始的方式,对flags加O_NONBLOCK; (注:如果想设置成非阻塞,这样:flags&~O_NONBLOCK)

方法2: recv, send函数的参数,最后一个参数设置成 MSG_DONTWAIT,如下:

recv(sockfd, buff, buff_size, MSG_DONTWAIT);
send(sockfd, buff, buff_size, MSG_DONTWAIT);

对当次的函数,为非阻塞。

普通文件:

方法1: open函数的第二个参数加上 O_NONBLOCK,函数说明如下:

#include <fcntl.h>int open(const char *pathname, int oflag, ... /* mode_t mode */);
open函数用来打开或创建一个文件,若成功返回文件描述符,否则返回-1。
pathname是要打开或创建文件的名字。
oflag参数是下列一个或多个常量执行按位或运算的结果杀
O_RDONLY  只读打开
O_WRONLY  只写打开
O_RDWR 读写打开
上面三个常量必须指定一个并且只能指定一个,下面一些常量则是可选的:
O_APPEND  将写入追加到文件的尾端
O_CREAT 若文件不存在,则创建它。使用该选项时,需要第三个参数mode,用来指定新文件的访问权限位
O_EXCL 如果同时指定了O_CREAT,而文件已经存在,则会出错
O_TRUNC 如果此文件存在,而且为只写或读写模式成功打开,则将其长度截短为0
O_NOCTTY 如果pathname指的是终端设备,则不将该设备分配作为此进程的控制终端
O_NONBLOCK 如果pathname指的是一个FIFO文件、块设备文件或字符设备文件,则此选项将文件的本次打开操作和后续的I/O操作设置为非阻塞模式

方法2,同socket的方法1,用F_SETFL和flags|O_NONBLOCK.

消息队列:

msgsnd和msgrcv的最后一个参数加上 IPC_NOWAIT:

int  msgsnd (int msqid,  const void *ptr,  size_t length, IPC_NOWAIT) ;

参数flag的值可以指定为IPC_NOWAIT。这类似于文件IO的非阻塞IO标志。若消息队列已满,则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。
如果没有指定IPC_NOWAIT,则进程阻塞直到下述情况出现为止:①有空间可以容纳要发送的消息 ②从系统中删除了此队列(返回EIDRM“标识符被删除”)③捕捉到一个信号,并从信号处理程序返回(返回EINTR) ssize_t msgrcv (int msqid, void* ptr, size_t length, long type, IPC_NOWAIT) ; 参数ptr指定所接收消息的存放位置。参数length指定了数据部分大小(只想要多长的数据)
参数type指定希望从队列中读出什么样的消息。
type == 0 返回队列中的第一个消息
type > 0 返回队列中消息类型为type的第一个消息
type < 0 返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个。则取类型值最小的消息。
(如果一个消息队列由多个客户进程和一个服务器进程使用,那么type字段可以用来包含客户进程的进程ID) 参数flag可以指定为IPC_NOWAIT,使操作不阻塞。

这类似于文件IO的非阻塞IO标志。比如msgsnd,若消息队列已满,则指定IPC_NOWAIT使得msgsnd立即出错返回EAGAIN。

阻塞与非阻塞的IO网络读写的更多相关文章

  1. 网络IO之阻塞、非阻塞、同步、异步总结

    网络IO之阻塞.非阻塞.同步.异步总结 1.前言 在网络编程中,阻塞.非阻塞.同步.异步经常被提到.unix网络编程第一卷第六章专门讨论五种不同的IO模型,Stevens讲的非常详细,我记得去年看第一 ...

  2. IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞的比较,recv参数对性能的影响—O_NONBLOCK(open使用)、IPC_NOWAIT(msgrcv)、MSG_DONTWAIT(re

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:       基本概念: 阻塞IO:: socket 的阻塞模式 ...

  3. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  4. 网络IO之阻塞、非阻塞、同步、异步总结【转】

    1.前言 在网络编程中,阻塞.非阻塞.同步.异步经常被提到.unix网络编程第一卷第六章专门讨论五种不同的IO模型,Stevens讲的非常详细,我记得去年看第一遍时候,似懂非懂,没有深入理解.网上有详 ...

  5. Python网络编程-IO阻塞与非阻塞及多路复用

    前言 问题:普通套接字实现的服务端的缺陷 一次只能服务一个客户端!                         accept阻塞! 在没有新的套接字来之前,不能处理已经建立连接的套接字的请求 re ...

  6. IO多路复用,同步,异步,阻塞和非阻塞 区别

    一.什么是socket?什么是I/O操作? 我们都知道unix(like)世界里,一切皆文件,而文件是什么呢?文件就是一串二进制流而已,不管socket,还是FIFO.管道.终端,对我们来说,一切都是 ...

  7. IO多路复用,同步,异步,阻塞和非阻塞 区别(转)

    转自:http://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral 同步.异步 是 ...

  8. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别参考

    参考https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral IO复用,AI ...

  9. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别(百度)

    如果面试问到IO操作,这篇文章提到的问题,基本是必问,百度的面试官问我三个问题 (1)什么是NIO(Non-blocked IO),AIO,BIO (2) java IO 与 NIO(New IO)的 ...

随机推荐

  1. Redis 安装 启动 连接 配置 重启

    Linux下安装 ]# wget http://download.redis.io/releases/redis-2.8.17.tar.gz ]# .tar.gz ]# cd redis- ]# ma ...

  2. [STL][C++]MAP

    参考链接:http://blog.sina.com.cn/s/blog_61533c9b0100fa7w.html map头文件 #include <map> map添加数据: map&l ...

  3. Djnago的一些零碎知识点

    1.TEMPLATE_DIRS relative to the project folder http://stackoverflow.com/questions/9856683/using-pyth ...

  4. hdoj4906 Our happy ending(2014 Multi-University Training Contest 4)

    对于一个定长(size = n)的数列a, 若其存在“位置相关”的子集(含空集)使得该子集所有元素之和为k,那么将数列a计数. 其中数列a中任一元素a[i]在[0, l]内自由取值. 数据条件0≤n, ...

  5. Inviting Friends(二分+背包)

    Inviting Friends Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...

  6. LinkedList的实现原理

    转载:http://wiki.jikexueyuan.com/project/java-collection/linkedlist.html 概述 LinkedList 和 ArrayList 一样, ...

  7. Entity Framework 第三篇 实体特性声明

    Entity Framework中对实体的特性声明有着严格的要求 1.实体必须要有主键特性,但是如果实体没有主键特性那怎么办? public int ExecuteSqlCommand(string ...

  8. IOS Bug分析

    异常代码是SIGABRT.通常,  SIGABRT 异常是由于某个对象接收到未实现的消息引起的. 或者,用简单的话说,在某个对象上调用了不存在的方法. iOS应用崩溃日志分析 分析iOS Crash文 ...

  9. 查看C语言的方法名

    1,打开 Visual Studio 2008 x64 Win64 命令提示 2,查看dumpbin  –exports  [C动态库的路径]

  10. eclipse 恢复SVN无法还原的文件 svn使用了还原,但本地的没有提交找回没提交代码的方法

    http://blog.sina.com.cn/s/blog_750167060102vd2n.html