通常来说,从普通文件读数据,无论你是采用 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的更多相关文章

  1. boot asio 非阻塞同步编程---非阻塞的accept和receive。

    boot asio 非阻塞同步编程---非阻塞的accept和receive. 客户端编程: #include<boost/timer.hpp> #include <iostream ...

  2. linux 客户端 Socket 非阻塞connect编程

    开发测试环境:虚拟机CentOS,windows网络调试助手        非阻塞模式有3种用途        1.三次握手同时做其他的处理.connect要花一个往返时间完成,从几毫秒的局域网到几百 ...

  3. linux网络编程中阻塞和非阻塞socket的区别

    读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...

  4. socket编程 —— 非阻塞socket (转)---例子已上传至文件中

    在上一篇文章 <socket编程——一个简单的例子> http://blog.csdn.net/wind19/archive/2011/01/21/6156339.aspx 中写了一个简单 ...

  5. UNIX网络编程——非阻塞connect:时间获取客户程序

    #include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...

  6. python 并发编程 非阻塞IO模型

    非阻塞IO(non-blocking IO) Linux下,可以通过设置socket使其变为non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图 ...

  7. UNIX网络编程-非阻塞connect和非阻塞accept

    1.非阻塞connect 在看了很多资料之后,我自己的理解是:在socket发起一次连接的时候,这个过程需要一段时间来将三次握手的过程走完,如果在网络状况不好或者是其他的一些情况下,这个过程需要比较长 ...

  8. UNIX网络编程——非阻塞accept

    当有一个已完成的连接准备好被accept时,select将作为可读描述符返回该连接的监听套接字.因此,如果我们使用select在某个监听套接字上等待一个外来连接,那就没有必要把监听套接字设置为非阻塞, ...

  9. UNIX网络编程——非阻塞connect: Web客户程序

    非阻塞的connect的实现例子出自Netscape的Web客户程序.客户先建立一个与某个Web服务器的HTTP连接,再获取一个主页.该主页往往含有多个对于其他网页的引用.客户可以使用非阻塞conne ...

  10. UNIX网络编程——非阻塞connect

    当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三次握手继续进行.我们接着使用select检测这个连接或成功或失败的已建 ...

随机推荐

  1. HTML5 Canvas 六角光阑动态效果

    光阑是光具组件中光学元件的边缘.框架或特别设置的带孔屏障,本人实现了结构比较简单的六角光阑,效果有点像宇航员在徐徐张开的飞船舷窗中看到逐渐完整的地球,下面四张图可以感受一下. 当然看动态效果才能真正体 ...

  2. Laravel之命令

    一.创建命令 php artisan make:console SendEmails 上述命令将会生成一个类app/Console/Commands/SendEmails.php,当创建命令时,--c ...

  3. sql server内置函数

    MSDN标准文档:https://msdn.microsoft.com/zh-cn/library/ff848784(v=sql.120).aspx 配置函数 select @@servername ...

  4. window.name实现跨域数据传输

    偶然间碰到个问题,通过JS给window.name赋值数组情况下,在firefox与chrome下会转换为字符串类型,在IE11下则显示正常.不说了,上图(firefox下): 代码: <scr ...

  5. c#关于路径的总结(转) 虚拟路径波浪号~和斜杠/的区别

    c#关于路径的总结(转)   来源:http://www.cnblogs.com/yugongmengjiutian/articles/5521165.html 前一段时间写代码时经常遇到获取路径问题 ...

  6. sklearn--feature extract--人脸识别

    1.原始数据加载 import matplotlib.pyplot as plt from sklearn.datasets import fetch_lfw_people people=fetch_ ...

  7. Laravel 数据库实例教程 —— 使用DB门面操作数据库

    Laravel支持多种数据库,包括MySQL.Postgres.SQLite和SQL Server,在Laravel中连接数据库和查询数据库都非常简单,我们可以使用多种方式与数据库进行交互,包括原生S ...

  8. spring源码解析之IOC容器(二)------加载和注册

    上一篇跟踪了IOC容器对配置文件的定位,现在我们继续跟踪代码,看看IOC容器是怎么加载和注册配置文件中的信息的.开始之前,首先我们先来了解一下IOC容器所使用的数据结构-------BeanDefin ...

  9. Http调试工具-Fiddler使用指引

    转自:http://my.oschina.net/u/1388024/blog/186886#OSC_h1_9 目录[-] Fiddler是什么? Fiddler能做什么? 从哪里下载? 安装: 初次 ...

  10. linux recv函数返回值分析

    函数原型: ssize_t recv(int sockfd, void *buf, size_t len, int flags); 该函数第一个参数制定接收端套接字描述符; 第二个参数指明一个缓冲区, ...