Linux环境下用于I/O多路复用的系统函数select浅析

在C程序中,select函数定义于sys/select.h头文件中,是用于I/O多路复用的一个系统调用函数。该函数用于监视的文件描述符的变化情况–可读、可写或者异常。

/* According to POSIX.1-2001 */
#include <sys/select.h>

/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
    fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

一、select函数参数说明
nfds – 最大文件描述符+1
readfds - fd_set type 类型,只读的描述符集
writefds - fd_set type 类型,只写的描述符集
errorfds – fd_set type 类型,错误的描述符集
timeout – 超时等待时间

#include <sys/time.h>

struct timeval {
    long    tv_sec;         /* seconds */
    long    tv_usec;        /* microseconds */
};

为了维护fd_set类型的参数,会使用下面四个宏:FD_SET(), FD_CLR(), FD_ZERO() 和 FD_ISSET()。

二、代码分析

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

#define TIMEOUT 10
// 设置超时时间秒数
#define MAX_LEN 4096
// 设置buffer最大字节数长度

int main(void)
{
	fd_set readfds;
	struct timeval tv;
	int retval;

	FD_ZERO(&readfds);
	FD_SET(STDIN_FILENO, &readfds);

	tv.tv_sec = TIMEOUT;
	tv.tv_usec = 0;

	// 万事俱备,只等非阻塞
	retval = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);

	// 返回值为-1,出错。
	if(retval < 0) {
		perror("select() error\n");
		return 1;
	}
	// 返回值为正数,可读。
	else if(retval) {
		// 测试一下,其实没必要。结果是肯定的。
		if(FD_ISSET(STDIN_FILENO, &readfds)) {
			printf("Data is available now.\n");
			char buf[MAX_LEN+1];
			int len;
			len = read(STDIN_FILENO, buf, MAX_LEN);
			
			if(len == -1) {
				perror("read() error\n");
				return 1;
			}
			else {
				buf[len] = '\0';
				printf("read:\t%s\n", buf);
			}
		}
	}
	// 返回值为0,超时,还是无数据可读。
	else {
		printf("No data within %d seconds.\n", TIMEOUT);
	}
	exit(EXIT_SUCCESS);
}

三、运行结果

[root@localhost workspace]# gcc testselect.c -o testselect -Wall
[root@localhost workspace]# ./testselect
HELLO WORLD
Data is available now.
read:   HELLO WORLD

[root@localhost workspace]# ./testselect
No data within 10 seconds.

Leave a Reply

Your email address will not be published. Required fields are marked *