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

一 阻塞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写端和上面一样

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非阻塞 I/O 操作是指在进行输入/输出操作时,不会阻塞程序的执行。在传统的阻塞 I/O 操作中,当程序调用读取或写入数据的函数时,如果数据还没有准备好或无法立即写入,程序会一直等待直到操作完成才能继续执行其他任务。这种等待会导致程序阻塞,无法同时处理其他任务或响应其他事件。 而非阻塞 I/O 操作则允许程序在进行输入/输出操作时立即返回,而不需要等待操作完成。如果数据还没有准备好或无法立即写入,非阻塞操作会立即返回一个错误码或特定的状态码,让程序可以继续执行其他任务或检查其他事件。 使用非阻塞 I/O 可以实现异步的 I/O 处理,使程序能够同时处理多个 I/O 操作或响应其他事件,提高程序的并发性和响应性能。在非阻塞模式下,程序可以定期轮询或使用回调函数等方式来检查 I/O 操作的状态,当数据准备好或可以写入时再进行实际的读取或写入操作。 需要注意的是,非阻塞 I/O 操作需要程序对返回的状态进行处理,并根据情况决定下一步的操作。这可能涉及到循环轮询、状态机设计、事件驱动等技术。同时,非阻塞 I/O 操作也可能会增加代码的复杂性,因为需要处理异步的操作和状态管理。 非阻塞 I/O 在网络编程中特别常见,可以用于同时处理多个网络连接或请求,提高系统的可扩展性和性能。在操作系统中,通常会提供相应的机制或函数来实现非阻塞 I/O,如使用 `fcntl()` 函数设置文件描述符的非阻塞属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值