select
select
函数在网络编程中用于监视多个文件描述符,查看它们是否有可读、可写或发生异常情况的条件满足。它是一种多路复用技术,使得程序可以同时监视多个文件描述符而不需要多线程或多进程。
函数原型
int select(int nfds,
fd_set *_Nullable restrict readfds,
fd_set *_Nullable restrict writefds,
fd_set *_Nullable restrict exceptfds,
struct timeval *_Nullable restrict timeout);
参数解释
-
int nfds
:- 这个参数指定所有文件描述符集合中最大文件描述符值加1。即,它是集合中所有文件描述符值中的最大值加1。
- 例如,如果
readfds
中有文件描述符3
和5
,那么nfds
应该是6
。
-
fd_set *readfds
:- 一个指向
fd_set
类型的指针,用于指示要检查可读性的文件描述符集合。 - 如果某个文件描述符在
readfds
集合中,并且在select
调用时有数据可读,则select
返回时,该文件描述符会保留在readfds
集合中。
- 一个指向
-
fd_set *writefds
:- 一个指向
fd_set
类型的指针,用于指示要检查可写性的文件描述符集合。 - 如果某个文件描述符在
writefds
集合中,并且在select
调用时可以写数据,则select
返回时,该文件描述符会保留在writefds
集合中。
- 一个指向
-
fd_set *exceptfds
:- 一个指向
fd_set
类型的指针,用于指示要检查异常情况的文件描述符集合。 - 如果某个文件描述符在
exceptfds
集合中,并且在select
调用时有异常情况(如带外数据),则select
返回时,该文件描述符会保留在exceptfds
集合中。
- 一个指向
-
struct timeval *timeout
:- 一个指向
timeval
结构的指针,用于指定select
调用的超时时间。 - 结构体定义如下:
struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ };
- 如果
timeout
为NULL
,select
将无限期地等待,直到一个文件描述符变得可读、可写或发生异常。 - 如果
timeout
的值为{0, 0}
,select
将立即返回。
- 一个指向
返回值
-
成功时:
- 返回值为就绪的文件描述符的数量(即有多少个文件描述符满足了可读、可写或异常情况)。
- 这些文件描述符会保留在相应的集合中,其他的会被移除。
-
错误时:
- 返回
-1
,并设置errno
以指示错误原因。
- 返回
示例代码
以下是一个使用 select
函数的示例,监视标准输入是否有数据可读:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
int main() {
fd_set readfds;
struct timeval timeout;
int ret;
// 初始化文件描述符集合
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
// 设置超时时间为5秒
timeout.tv_sec = 5;
timeout.tv_usec = 0;
// 调用select函数
ret = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout);
if (ret == -1) {
perror("select");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("Timeout occurred! No data after 5 seconds.\n");
} else {
if (FD_ISSET(STDIN_FILENO, &readfds)) {
char buffer[100];
read(STDIN_FILENO, buffer, sizeof(buffer));
printf("Data: %s\n", buffer);
}
}
return 0;
}
这个示例程序会在5秒内等待标准输入(通常是键盘)上是否有数据输入。如果有数据,它会读取并打印出来;如果5秒内没有数据输入,程序会打印超时信息并退出。