linux c编程:非阻塞I/O
通常来说,从普通文件读数据,无论你是采用 fscanf,fgets 也好,read 也好,一定会在有限的时间内返回。但是如果你从设备,比如终端(标准输入设备)读数据,只要没有遇到换行符(‘\n’),read 一定会“堵”在那而不返回。还有比如从网络读数据,如果网络一直没有数据到来,read 函数也会一直堵在那而不返回。
read 的这种行为,称之为 block,一旦发生 block,本进程将会被操作系统投入睡眠,直到等待的事件发生了(比如有数据到来),进程才会被唤醒。
系统调用 write 同样有可能被阻塞,比如向网络写入数据,如果对方一直不接收,本端的缓冲区一旦被写满,就会被阻塞。
比如下面的程序
int main() {
char buf[10];
int len;
while(1) {
// STDIN_FILENO 是标准输入的描述符,它的值是 0. STDOUT_FILENO 是标准输出的描述符,它的值是 1.
len = read(STDIN_FILENO, buf, 10);
write(STDOUT_FILENO, buf, len);
}
return 0;
}
gcc –o main.out main.c
./main.out
如果不向终端输入数据,程序将永远阻塞在read系统调用处。要规避这个问题,我们就需要用到非阻塞的IO。
对于一个给定的描述符有两种方法对其指定非阻塞I/O:
1) 如果调用open获得描述符,则可指定O_NONBLOCK标志
2) 对于已打开的一个描述符,则可调用fcntl,由该函数打开O_NONBLOCK文件状态标志。
程序如下:
set_f1是设置读取的方式为非阻塞,clr_f1则是清除非阻塞的方式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
void set_f1(int fd,int flags){
int val;
if ((val=fcntl(fd,F_GETFL,0)) < 0)
printf("fcntl F_GETFL
error");
val|=flags;
if (fcntl(fd,F_SETFL,val) < 0)
printf("fcntl F_sETFL
error");
}
void clr_f1(int fd,int flags){
int val;
if ((val=fcntl(fd,F_GETFL,0)) < 0)
printf("fcntl F_GETFL
error");
val&=~flags;
if (fcntl(fd,F_SETFL,val) < 0)
printf("fcntl F_sETFL
error");
}
char buf[50000];
int main()
{
int ntowrite,nwrite;
char *ptr;
ntowrite=read(STDIN_FILENO,buf,sizeof(buf));
fprintf(stderr,"read %d bytes\n",ntowrite);
set_f1(STDOUT_FILENO,O_NONBLOCK);
ptr=buf;
while(ntowrite > 0){
errno=0;
nwrite=write(STDOUT_FILENO,ptr,ntowrite);
fprintf(stderr,"nwrite=%d,errno=%d\n",nwrite,errno);
if(nwrite > 0){
ptr+=nwrite;
ntowrite-=nwrite;
}
}
clr_f1(STDOUT_FILENO,O_NONBLOCK);
return 0;
}
若标准输出是普通文件,则可以期望write只执行一次
root@maple-VirtualBox:/home/maple/codeblock_prj/func_test#
./main.out < /etc/services > temp.file
read 19605 bytes
nwrite=19605,errno=0
root@maple-VirtualBox:/home/maple/codeblock_prj/func_test# ls -al temp.file
-rw-r--r-- 1 root root 19605 8月 12 15:33
temp.file
但是,如果标准输出是终端。则有时会返回错误。
root@maple-VirtualBox:/home/maple/codeblock_prj/func_test#
cat stderr.out
read 19605 bytes
nwrite=14907,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=-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=-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=-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=-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=-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=-1,errno=11
nwrite=-1,errno=11
nwrite=4698,errno=0
程序发出了多个write调用,但是只有部分真正输出了数据。其他的都只返回了错误。这种形式的循环成为轮询。在多用户系统上会浪费CPU时间。
linux c编程:非阻塞I/O的更多相关文章
- boot asio 非阻塞同步编程---非阻塞的accept和receive。
boot asio 非阻塞同步编程---非阻塞的accept和receive. 客户端编程: #include<boost/timer.hpp> #include <iostream ...
- linux 客户端 Socket 非阻塞connect编程
开发测试环境:虚拟机CentOS,windows网络调试助手 非阻塞模式有3种用途 1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...
- linux网络编程中阻塞和非阻塞socket的区别
读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...
- socket编程 —— 非阻塞socket (转)---例子已上传至文件中
在上一篇文章 <socket编程——一个简单的例子> http://blog.csdn.net/wind19/archive/2011/01/21/6156339.aspx 中写了一个简单 ...
- UNIX网络编程——非阻塞connect:时间获取客户程序
#include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...
- python 并发编程 非阻塞IO模型
非阻塞IO(non-blocking IO) Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图 ...
- UNIX网络编程-非阻塞connect和非阻塞accept
1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...
- UNIX网络编程——非阻塞accept
当有一个已完成的连接准备好被accept时,select将作为可读描述符返回该连接的监听套接字.因此,如果我们使用select在某个监听套接字上等待一个外来连接,那就没有必要把监听套接字设置为非阻塞, ...
- UNIX网络编程——非阻塞connect: Web客户程序
非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...
- UNIX网络编程——非阻塞connect
当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...
随机推荐
- 《大话操作系统——做坚实的project实践派》(3)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbG1ub3M=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...
- OpenCV2学习笔记(十五):利用Cmake高速查找OpenCV函数源代码
在使用OpenCV时,在对一个函数的调用不是非常了解的情况下,通常希望查到该函数的官方声明.而假设想进一步研究OpenCV的函数,则必须深入到源码. 在VS中我们能够选中想要查看的OpenCV函数,点 ...
- hibernate学习系列-----(3)Session 缓存和持久化生命周期以及Session 基本操作
Session缓存原理 为了能够在控制台更好的看到我们的hibernate干了些什么,可以在hibernate.cfg.xml文件中写入如下配置: <!-- print all generate ...
- STL学习笔记(仿函数)
仿函数(Functors) 仿函数(functor),就是使一个类的使用看上去象一个函数.其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了. 例如我们定义一个 ...
- IIS相关知识和经验的碎皮化记录
1.IIS(Internet Information Services)网站本机可以访问,局域网其他机器无法访问 导致这个问题之一是防火墙规则,解决办法如下: 1)[开始]打开[控制面板],选择[WI ...
- SpringCloud系列四:实现Eureka Server的高可用并将应用注册到Eureka Sever集群上
1. 回顾 上一篇博客中,实现了单节点的Eureka Server.Eureka Client会定时连接Eureka Server,获取注册表中的信息并缓存到本地.微服务在消费远程API时总是使用本地 ...
- Maven环境下搭建SSH框架之Spring整合Hibernate
© 版权声明:本文为博主原创文章,转载请注明出处 1.搭建环境 Spring:4.3.8.RELEASE Hibernate:5.1.7.Final MySQL:5.7.17 注意:其他版本在某些特性 ...
- atitit.基于bat cli的插件管理系统.doc
atitit.基于bat cli的插件管理系统.doc /AtiPlatf/src_atibrow/com/attilax/cmd/CmdX.java pathx.isWebPathMode=true ...
- 安卓手机的后门控制工具SPADE
SPADE,一款安卓手机的后门控制工具,安全研究人员可以以此了解和研究安卓后门原理. 首先,我们从网站www.apk4fun.com下载apk文件,如ccleaner.然后,我们安装spade git ...
- 在Servlet的GenericServlet类中为什么有两个init()方法
想要搞清楚这件事情,必须先了解Servlet容器调用Servlet的过程.调用过程如下 首次访问该Servlet1.调用init(ServletConfig config) 进行初始化,Servlet ...