看我之前的文章就知道,一般对于网络读的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. ACM题目————字串数

    Description 一个A和两个B一共可以组成三种字符串:"ABB","BAB","BBA". 给定若干字母和它们相应的个数,计算一共可 ...

  2. File和URL的getPath()方法区别

    java.io.File对象的getPath()方法返回文件的全路径名.如果是目录返回目录路径且结尾没有"\".如果是文件包含文件名. java.io.File对象的getName ...

  3. Unity脚本在层级面板中的执行顺序测试1

    第二篇测试循环时和动态创建时的调用顺序:LINK 测试版本Unity4.6.因为新版本对Transform的排序做了改变,所以不排除旧版本的测试结果不一样.测试时,使用Awake中添加Debug.lo ...

  4. Linux高级变量

    http://blog.chinaunix.net/uid-27040051-id-3450991.html 高级变量 基本形式 [1].变量扩展 格式 ${变量名称} [2].命令扩展 格式 $(命 ...

  5. MySQL bin-log 日志清理方式

    MySQL bin-log 作用   1.数据恢复:如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失. 2.主从服务器之间同步数据:主 ...

  6. JAVA基础知识之JVM-——自定义类加载器

    JVM中除了根加载器之外其他加载器都是ClassLoader的子类实例, 可以通过扩展ClassLoader的子类,通过重写方法来实现自定义的类加载器. ClassLoader中有两个关键的方法如下, ...

  7. linux文件描述符--转载

    转自:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录 ...

  8. 项目文件中含有两个config文件,app.config与app1.config,如何获取app1.config中的配置

    想要通过配置文件配置C#前台画面,好奇做了以下测试:在项目中新建了app.config与app1.config两个配置文件,请教一下各位高手如果想从app1.config中读取配置信息应该如何读取?采 ...

  9. SqlSever基础 select 用+号连接两个字符串

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  10. [POJ1222]EXTENDED LIGHTS OUT(高斯消元,异或方程组)

    题目链接:http://poj.org/problem?id=1222 题意:开关是四连通的,每按一个就会翻转自己以及附近的四个格(假如有).问需要翻转几个,使他们都变成关. 把每一个灯看作一个未知量 ...