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检测这个连接或成功或失败的已建 ...
随机推荐
- P6 EPPM 16 R1安装和配置文档
白桃花心木P6企业项目组合管理文档库 描述 链接 下载 零件号 16 R1用户和集成文档 查看库 下载 E68199-01 16 R1安装和配置文档 查看库 下载 E68198-01 描述 链接 ...
- 谷歌安卓UI自动化测试策略
中文翻译版: 为了使大家确信"应做单元测试,就一定能做单元测试",谷歌测试工程师Mona El Mahdy专门写了一篇博客,提出了几种执行安卓应用用户界面单元测试的方法.Mahdy ...
- centos7 安装docker后启动报错
启动docker $ sudo systemctl start docker 报错. 查看状态: $ systemctl status docker.service -l 加 -l 有的行信息很长 ...
- Spark中经常使用工具类Utils的简明介绍
<深入理解Spark:核心思想与源代码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源代码分析>一书正式出版上市 <深入理解Spark:核心思想与源代码分析 ...
- vi 详解
1.vi的基本概念 基本上vi可以分为三种状态,分别是命令模式(command mode).插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: ...
- C语言include预处理命令与多文件编译
#include预处理命令几乎使我们在第一次接触C的时候就会碰到的预处理命令,可我现在还不怎么清楚,这次争取一次搞懂. 一.#include预处理指令的基本使用 预处理指令可以将别处的源代码内容插入到 ...
- 篇三、开发前知识补充:Android的长度单位和屏幕分辨率,这个也是转载~~
这篇文章有点早,不过很实用.单位的实用看最后的红色标注的部分. 屏幕分辨率基础 1.术语和概念 术语 说明 备注 Screen size(屏幕尺寸) 指的是手机实际的物理尺寸,比如常用的2.8英寸,3 ...
- linux下性能测试工具netperf使用
一.功能简介 netperf是一款针对网络性能的测试工具,主要基于TCP或UDP的传输.根据应用的不同,可以进行批量数据传输(bulk data transfer)模式和请求/应答(request/r ...
- Linux安装php-7.0.16,完成php和apache的配置
Linux安装php-7.0.16,完成php和apache的配置 版本:php-7.0.16.tar.gz,libxml2-2.9.2.tar.gz(php需要它的支持,首先安装它) 说明 ...
- VMWare虚拟机下为Ubuntu 12.04.2配置静态IP(NAT方式)
http://www.cnblogs.com/objectorl/archive/2012/09/27/vmware-ubuntu-nat-static-ip-settings.html 参考以上方式 ...