Linux下的非阻塞IO(一)
非阻塞IO是相对于传统的阻塞IO而言的。
我们首先需要搞清楚,什么是阻塞IO。APUE指出,系统调用分为两类,低速系统调用和其他,其中低速系统调用是可能会使进程永远阻塞的一类系统调用。但是与磁盘IO有关的系统调用是个例外。
我们以read和write为例,read函数读取stdin,如果是阻塞IO,那么:
如果我们不输入数据,那么read函数会一直阻塞,一直到我们输入数据为止。
如果是非阻塞IO,那么:
如果存在数据,读取然后返回,如果没有输入,那么直接返回-1,errno置为EAGAIN
我们用write做一个实验:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h> char buf[500000]; int main(int argc, const char *argv[])
{
int ntowrite, nwrite; ntowrite = read(STDIN_FILENO, buf, sizeof buf);
fprintf(stderr, "read %d bytes\n", ntowrite); activate_nonblock(STDOUT_FILENO, O_NONBLOCK); char *ptr = buf;
int nleft = ntowrite; //剩余的字节数
while(nleft > 0)
{
errno = 0;
nwrite = write(STDOUT_FILENO, ptr, nleft);
fprintf(stderr, "nwrite = %d, errno = %d\n", nwrite, errno); if(nwrite > 0)
{
ptr += nwrite;
nleft -= nwrite;
}
} deactivate_nonblock(STDOUT_FILENO); return 0;
}
该程序向标准输出写入500000个字节。
如果使用:
./test < test.mkv > temp.file
那么输出结果为:
read 500000 bytes
nwrite = 500000, errno = 0
因为磁盘IO的速度较快,所以一次就可以写入,下面我们使用终端:
./test < test.mkv 2> stderr.txt
这行命令将500000的内容打印到屏幕上,同时将fprintf记录的信息通过标准错误流写入stderr.txt。
我们查看stderr.txt文件:
read 500000 bytes
nwrite = 12708, errno = 0
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = 11687, errno = 0
nwrite = -1, errno = 11
…………………………………………..
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = -1, errno = 11
nwrite = 1786, errno = 0
采用命令统计了一下,总计read次数为15247次,其中返回-1次数为15203次,说明成功读取次数为44次。
上面例子中,这种采用非阻塞IO的方式称为“轮询”,显然这是一种低效的方式,非阻塞IO通常与IO复用模型结合使用。
另外,将fd设置为阻塞和非阻塞的函数代码如下:
void activate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if (flags == -1)
ERR_EXIT("fcntl");
flags |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("fcntl");
} void deactivate_nonblock(int fd)
{
int ret;
int flags = fcntl(fd, F_GETFL);
if (flags == -1)
ERR_EXIT("fcntl");
flags &= ~O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -1)
ERR_EXIT("fcntl");
}
未完待续。
Linux下的非阻塞IO(一)的更多相关文章
- linux函数的阻塞与非阻塞IO及错误处理
1.阻塞是指进程等待某一个事件的发生而处于等待状态不往下执行,如果等待的事件发生了则会继续执行该进程.调用系统阻塞函数可能会导致进程阻塞进入睡眠状态. 2.阻塞IO之read读取键盘输入数据 3.li ...
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)
IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...
- Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO
背景 整理之前学习socket编程的时候复习到了多路复用,搜索了有关资料,了解到多路复用也有局限性,本着打破砂锅问到底的精神,最终找到了关于IO模型的知识点. 在<Unix网络编程>一书中 ...
- Linux非阻塞IO(六)使用poll实现非阻塞的服务器端
关于poll模型监听的事件以及返回事件,我们定义宏如下: #define kReadEvent (POLLIN | POLLPRI) #define kWriteEvent (POLLOUT | PO ...
- Linux非阻塞IO(五)使用poll实现非阻塞的回射服务器客户端
前面几节我们讨论了非阻塞IO的基本概念.Buffer的设计以及非阻塞connect的实现,现在我们使用它们来完成客户端的编写. 我们在http://www.cnblogs.com/inevermore ...
- Linux非阻塞IO(四)非阻塞IO中connect的实现
我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ...
- Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合
上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...
- 《linux设备驱动开发详解》笔记——8阻塞与非阻塞IO
8.1 阻塞与非阻塞IO 8.1.0 概述 阻塞:访问设备时,若不能获取资源,则进程挂起,进入睡眠状态:也就是进入等待队列 非阻塞:不能获取资源时,不睡眠,要么退出.要么一直查询:直接退出且无资源时, ...
- Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现
本文我们来实现回射服务器的Buffer. Buffer的实现 上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ...
随机推荐
- Gradle for Android(一)
Gradle是一种基于Groovy的动态DSL,而Groovy语言是一种基于jvm的动态语言.这里只分享实际开发中会用到的场景,您不需要去学习Groovy语言,知道Java的您是很容易阅读Groovy ...
- [bzoj1833][ZJOI2010]count 数字计数——数位dp
题目: (传送门)[http://www.lydsy.com/JudgeOnline/problem.php?id=1833] 题解: 第一次接触数位dp,真的是恶心. 首先翻阅了很多很多一维dp,因 ...
- eclipse keys
Navigate Open Declaration F3 Editing Script Source Source Mark Occurrences Alt+Shift+O Editing PHP s ...
- V4L2 camera 驱动 capture测试程序【转】
转自:http://blog.csdn.net/kickxxx/article/details/6336346 在网上找了一个测试程序, 看了看,是根据capture.c修改的.测试步骤如下 . gc ...
- 8.OpenStack网络组件
添加网络组件 安装和配置控制器节点 创建数据库 mysql -uroot -ptoyo123 CREATE DATABASE neutron; GRANT ALL PRIVILEGES ON neut ...
- 【推荐】nodeJS后台守护进程-forever
A simple CLI tool for ensuring that a given node script runs continuously (i.e. forever) 本地执行: npm i ...
- openstack token
在openstack的token中,包含如下: 'domain', {'id': None, 'name': None}'expires', datetime.datetime(2017, 8, 9, ...
- Laravel实现用户名或密码登录
要实现用户名或密码登录,这就要用到强大的filter_var函数 该函数通过指定的过滤器过滤变量,可以判断输入值是否是数字.是否是字符串.是否是邮箱.是否是IP等等,不用写麻烦的正则 $type = ...
- python 将windows字体中的汉字生成图片的方法
#encoding: utf-8import osimport pygame chinese_dir = '黑体常规'if not os.path.exists(chinese_dir): os.mk ...
- POJ1741 Tree(树的点分治)
题目给一棵边带权的树,统计路径长度<=k的点对数. 楼教主男人八题之一,分治算法在树上的应用. 一开始看论文看不懂,以为重心和距离那些是一遍预处理得来的..感觉上不敢想每棵子树都求一遍重心和距离 ...