网络编程:阻塞IO和非阻塞IO(fcntl函数说明)

  • Post author:
  • Post category:其他


一 阻塞IO

1.1概念:

阻塞I/O 模式是最普遍使用的I/O 模式,大部分程序使用的都是阻塞模式的I/O 。

缺省情况下,套接字建立后所处于的模式就是阻塞I/O 模式。

前面学习的很多读写函数在调用过程中会发生阻塞。

读操作中的read、recv、recvfrom

写操作中的write、send

其他操作:accept、connect

以读阻塞为例:

当进程执行到读函数的时候

如果缓冲区里面有内容,程序读取完内容之后就继续向下执行,

如果缓冲区里面没有内容,进程就会进入休眠态,直到缓冲区里面有内容了

内核会唤醒该进程,然后进程过来读取缓冲区的内容,然后继续向下执行。

写操作也是会阻塞的,当写缓冲区满的时候就会阻塞

1.2代码实现:

1.2.1读端

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(){
    int fd1 = open("./fifo1", O_RDONLY);
    int fd2 = open("./fifo2", O_RDONLY);
    int fd3 = open("./fifo3", O_RDONLY);

    char buff1[128] = {0};
    char buff2[128] = {0};
    char buff3[128] = {0};

    while(1){
        memset(buff1, 0, 128);
        read(fd1, buff1, 128);
        printf("buff1:[%s]\n", buff1);

        memset(buff2, 0, 128);
        read(fd2, buff2, 128);
        printf("buff2:[%s]\n", buff2);

        memset(buff3, 0, 128);
        read(fd3, buff3, 128);
        printf("buff3:[%s]\n", buff3);
    }

    close(fd1);
    close(fd2);
    close(fd3);

    return 0;
}

1.2.2写端(三个写端都是一样的,只不过名字不一样)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(){
    int fd = open("./fifo1", O_WRONLY);

    char buff[128] = {0};

    while(1){
        memset(buff, 0, 128);
        fgets(buff, 128, stdin);
        buff[strlen(buff)-1] = '\0';
        write(fd, buff, 128);
    }

    close(fd);

    return 0;
}

二非阻塞IO

2.1概念

以读阻塞为例:

当进程执行到读函数的时候

如果缓冲区里面有内容,程序读取完内容之后就继续向下执行,

如果缓冲区里面没有内容,进程就不进入休眠态,而是立即返回一个错误

这种情况下就需要我们轮询去执行操作,这种操作是十分占用CPU的

一般不推荐使用

一般阻塞函数都有一个能设置非阻塞方式的选项

如 recv 和 recvfrom 的 MSG_DONTWAIT

waitpid 的 WNOHONG

O_NONBLOCK

对于read这种函数,本身是没有非阻塞选项的,这是可以使用 fcntl 函数来设置非阻塞

2.2fcntl函数的说明:

int flag = fcntl(fd, F_GETFL);//获取原来的状态
flag |= O_NONBLOCK;//添加非阻塞属性
fcntl(fd, F_SETFL, flag);//再设置回去

2.3代码说明:

2.3.1读端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(){
    int fd1 = open("./fifo1", O_RDONLY);
    int fd2 = open("./fifo2", O_RDONLY);
    int fd3 = open("./fifo3", O_RDONLY);

    char buff1[128] = {0};
    char buff2[128] = {0};
    char buff3[128] = {0};

    //将文件描述符都设置成非阻塞
    int flag = fcntl(fd1, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd1, F_SETFL, flag);

    flag = fcntl(fd2, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd2, F_SETFL, flag);

    flag = fcntl(fd3, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(fd3, F_SETFL, flag);

    while(1){
        memset(buff1, 0, 128);
        read(fd1, buff1, 128);
        printf("buff1:[%s]\n", buff1);

        memset(buff2, 0, 128);
        read(fd2, buff2, 128);
        printf("buff2:[%s]\n", buff2);

        memset(buff3, 0, 128);
        read(fd3, buff3, 128);
        printf("buff3:[%s]\n", buff3);

        //sleep(1);//此处的sleep(1) 是为了防止刷屏
            //能看到现象的,正常应该是没有的
            //如果没有这个sleep  使用 top可以看到
            //该进程 基本已经把CPU占满了
    }

    close(fd1);
    close(fd2);
    close(fd3);

    return 0;
}

2.3.2写端和上面一样



版权声明:本文为a2998658795原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。