分析多路IO复用的原理

分析多路IO复用的原理,实现SELECT的案例

多路I/O复用是现代网络编程中非常重要的技术,允许一个单独的线程或进程同时监视多个文件描述符(通常是套接字),从而能够在这些描述符之一准备好进行I/O操作时进行相应的处理。多路I/O复用的主要系统调用有selectpollepoll(在Linux上)。

以下是一个关于select的简单案例,展示了它的基本使用方法。

原理

select系统调用允许程序监视多个文件描述符,等待其中的一个或多个变为"就绪"状态(可读、可写或异常)。调用select时,程序可以指定三个文件描述符集(可读、可写和异常),以及一个超时时间。select会阻塞,直到:

  1. 一个或多个文件描述符就绪。
  2. 超时发生。
  3. 被信号中断。

使用步骤

  1. 初始化文件描述符集:使用FD_ZEROFD_SET等宏来初始化和设置文件描述符集。
  2. 调用select:传递文件描述符集和超时时间。
  3. 处理就绪文件描述符:检查哪些文件描述符就绪,并进行相应的处理。

示例代码:

以下是一个用 fd_setselect 的示例程序,演示了如何将监听文件描述符加入集合,并在 while 循环中判断哪些文件描述符已就绪。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>

int main() {
    int ret;
    char buff[1024];
    fd_set set, rset;
    int maxfd;
    struct timeval tv;

    // 初始化文件描述符集合
    FD_ZERO(&set);
    FD_SET(STDIN_FILENO, &set); // 将标准输入文件描述符加入集合
    maxfd = STDIN_FILENO;

    // 设置超时时间
    tv.tv_sec = 2;
    tv.tv_usec = 0;

    while (1) {
        rset = set; // 每次循环都要重置rset,因为select会修改它

        printf("Waiting for input...\n");
        ret = select(maxfd + 1, &rset, NULL, NULL, &tv);

        if (ret < 0) {
            perror("select");
            break;
        }

        if (ret == 0) {
            printf("Timeout occurred! No data after 2 seconds.\n");
            tv.tv_sec = 2; // 重新设置超时时间
            tv.tv_usec = 0;
            continue;
        }

        // 检查哪些文件描述符已就绪
        for (int i = 0; i <= maxfd; i++) {
            if (FD_ISSET(i, &rset)) {
                ret = read(i, buff, sizeof(buff) - 1);
                if (ret > 0) {
                    buff[ret] = '\0'; // 确保字符串以null结尾
                    printf("Received input: %s\n", buff);
                } else if (ret == 0) {
                    // 处理EOF
                    printf("EOF encountered on file descriptor %d\n", i);
                } else {
                    perror("read");
                }
            }
        }
    }

    return 0;
}

代码解释

  1. 初始化文件描述符集合

    FD_ZERO(&set);
    FD_SET(STDIN_FILENO, &set); // 将标准输入文件描述符加入集合
    maxfd = STDIN_FILENO;
    
  2. 设置超时时间

    tv.tv_sec = 2;
    tv.tv_usec = 0;
    
  3. 进入主循环

    while (1) {
        rset = set; // 每次循环都要重置rset,因为select会修改它
    
        printf("Waiting for input...\n");
        ret = select(maxfd + 1, &rset, NULL, NULL, &tv);
    
  4. 处理 select 返回值

    if (ret < 0) {
        perror("select");
        break;
    }
    
    if (ret == 0) {
        printf("Timeout occurred! No data after 2 seconds.\n");
        tv.tv_sec = 2; // 重新设置超时时间
        tv.tv_usec = 0;
        continue;
    }
    
  5. 检查哪些文件描述符已就绪

    for (int i = 0; i <= maxfd; i++) {
        if (FD_ISSET(i, &rset)) {
            ret = read(i, buff, sizeof(buff) - 1);
            if (ret > 0) {
                buff[ret] = '\0'; // 确保字符串以null结尾
                printf("Received input: %s\n", buff);
            } else if (ret == 0) {
                // 处理EOF
                printf("EOF encountered on file descriptor %d\n", i);
            } else {
                perror("read");
            }
        }
    }
    

通过这个示例,你可以看到如何使用 select 系统调用来监视标准输入,并在输入数据可用时读取数据并打印。每次 select 调用后,程序会检查哪些文件描述符已就绪,并对其进行处理。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值