通常来说,从普通文件读数据,无论你是采用 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. P6 EPPM 16 R1安装和配置文档

    白桃花心木P6企业项目组合管理文档库  描述 链接 下载 零件号  16 R1用户和集成文档 查看库 下载 E68199-01 16 R1安装和配置文档 查看库 下载 E68198-01 描述 链接 ...

  2. 谷歌安卓UI自动化测试策略

    中文翻译版: 为了使大家确信"应做单元测试,就一定能做单元测试",谷歌测试工程师Mona El Mahdy专门写了一篇博客,提出了几种执行安卓应用用户界面单元测试的方法.Mahdy ...

  3. centos7 安装docker后启动报错

    启动docker   $ sudo systemctl start docker 报错. 查看状态: $ systemctl status docker.service -l 加 -l 有的行信息很长 ...

  4. Spark中经常使用工具类Utils的简明介绍

    <深入理解Spark:核心思想与源代码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源代码分析>一书正式出版上市 <深入理解Spark:核心思想与源代码分析 ...

  5. vi 详解

    1.vi的基本概念 基本上vi可以分为三种状态,分别是命令模式(command mode).插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: ...

  6. C语言include预处理命令与多文件编译

    #include预处理命令几乎使我们在第一次接触C的时候就会碰到的预处理命令,可我现在还不怎么清楚,这次争取一次搞懂. 一.#include预处理指令的基本使用 预处理指令可以将别处的源代码内容插入到 ...

  7. 篇三、开发前知识补充:Android的长度单位和屏幕分辨率,这个也是转载~~

    这篇文章有点早,不过很实用.单位的实用看最后的红色标注的部分. 屏幕分辨率基础 1.术语和概念 术语 说明 备注 Screen size(屏幕尺寸) 指的是手机实际的物理尺寸,比如常用的2.8英寸,3 ...

  8. linux下性能测试工具netperf使用

    一.功能简介 netperf是一款针对网络性能的测试工具,主要基于TCP或UDP的传输.根据应用的不同,可以进行批量数据传输(bulk data transfer)模式和请求/应答(request/r ...

  9. 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需要它的支持,首先安装它) 说明 ...

  10. VMWare虚拟机下为Ubuntu 12.04.2配置静态IP(NAT方式)

    http://www.cnblogs.com/objectorl/archive/2012/09/27/vmware-ubuntu-nat-static-ip-settings.html 参考以上方式 ...