千锋教育-做有情怀、有良心、有品质的职业教育机构

手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

当前位置:首页  >  技术干货  > 深度解析select函数的返回值

深度解析select函数的返回值

来源:千锋教育
发布人:xqq
时间: 2023-11-24 23:27:21 1700839641

select函数是一个有着较复杂返回值的系统级函数,如果你使用过它,你就会知道这个返回值是一个按照文件描述符分成三类的系统级数据结构。下面我们将从多个方面对select函数的返回值做详细的阐述。

一、返回值格式及其含义


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

select函数的返回参数有3个,分别是readfds、writefds、以及exceptfds。来了解下这三个参数具体代表什么意思:

readfds是一个集合,其中包含一些文件描述符,在这些文件描述符中存在一些可读数据。 writefds是一个集合,其中包含一些文件描述符,在这些文件描述符中可以进行写操作而不会被阻塞。 exceptfds是一个集合,其中包含一些文件描述符,表示这些文件描述符的异常条件(如关闭连接、收到信号等)已经发生。

在接下来的小节中,我们会围绕这3个参数分别展开讲解,深入探究select函数的返回值的更多细节。

二、readfds的使用方法

readfds是select函数返回值的第一个参数,它的具体含义是有数据可以读取的文件描述符集合。当调用select函数时,会一直阻塞直到readfds中至少有一个文件描述符被设置,表示它们中至少有一个可以进行读操作且不会被阻塞。

下面是一个获取TCP/IP连接数据的例子:


int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

fd_set readSet;
FD_ZERO(&readSet);
FD_SET(sockfd, &readSet);

if (select(sockfd + 1, &readSet, NULL, NULL, NULL) < 0) {
    // TODO: 错误处理
}

char buffer[1024];
recv(sockfd, buffer, sizeof(buffer), 0);

在上述代码中,我们使用了select函数来等待从sockfd连接中读取数据。通过FD_ZERO和FD_SET将需要等待的文件描述符(sockfd)设置到readSet中,再将readSet作为select函数的参数,使其在readSet中有数据时返回。

三、writefds的使用方法

writefds是select函数返回值的第二个参数,它的具体含义是可以进行写入操作的文件描述符集合。当调用select函数时,会一直阻塞直到writefds中至少有一个文件描述符被设置,表示它们中至少有一个可以进行写操作且不会被阻塞。

下面是一个获取TCP/IP连接数据的例子:


int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

fd_set writeSet;
FD_ZERO(&writeSet);
FD_SET(sockfd, &writeSet);

if (select(sockfd + 1, NULL, &writeSet, NULL, NULL) < 0) {
    // TODO: 错误处理
}

char buffer[] = "hello world";
send(sockfd, buffer, strlen(buffer), 0);

在上述代码中,我们使用了select函数来等待从sockfd连接中写入数据。通过FD_ZERO和FD_SET将需要等待的文件描述符(sockfd)设置到writeSet中,再将writeSet作为select函数的参数,使其在writeSet中有数据时返回。

四、exceptfds的使用方法

exceptfds是select函数返回值的第三个参数,它的具体含义是异常文件描述符集合。当调用select函数时,会一直阻塞直到exceptfds中至少有一个文件描述符被设置,表示这些文件描述符有异常条件发生(如关闭连接、收到信号等)。

下面是一个监听TCP/IP连接异常的例子:


int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(12345);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
listen(sockfd, 1024);

int connfd = accept(sockfd, NULL, NULL);

fd_set exceptSet;
FD_ZERO(&exceptSet);
FD_SET(connfd, &exceptSet);

if (select(connfd + 1, NULL, NULL, &exceptSet, NULL) < 0) {
    // TODO: 错误处理
}

if (FD_ISSET(connfd, &exceptSet)) {
    // TODO: 处理异常
}

在上述代码中,我们使用了select函数来等待从connfd连接中的异常条件。通过FD_ZERO和FD_SET将需要等待的文件描述符(connfd)设置到exceptSet中,再将exceptSet作为select函数的参数,使其在exceptSet中有数据时返回。然后我们再使用FD_ISSET来判断是否有异常发生。

五、超时参数timeout的使用

select函数的最后一个参数是timeout,用于设置超时时间。它可以为NULL(表示一直阻塞到有数据到来),也可以设置为一个指向timeval结构体的指针(指定一个等待时间,在等待时间内如果没有数据到来,则select函数会超时并返回)。

下面是一个等待超时的例子:


fd_set readSet;
FD_ZERO(&readSet);
FD_SET(fileno(stdin), &readSet);

struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;

if (select(fileno(stdin) + 1, &readSet, NULL, NULL, &tv) < 0) {
    // TODO: 错误处理
}

if (FD_ISSET(fileno(stdin), &readSet)) {
    // TODO: 处理输入
} else {
    // TODO: 处理超时
}

在上述代码中,我们使用了select函数来等待从标准输入中的数据。通过FD_ZERO和FD_SET将需要等待的文件描述符(fileno(stdin))设置到readSet中,再将readSet作为select函数的参数,timeout设置为5秒时间。如果在5秒之内没有数据到来,则select函数会超时并返回。如果在5秒之内有数据到来,则FD_ISSET会返回真。

六、总结

本文从select函数的返回值格式及其含义、readfds的使用方法、writefds的使用方法、exceptfds的使用方法以及超时参数timeout的使用这五个方面对select函数的返回值做了深入的探索。以后在使用select函数时,希望读者们能够更加深入地理解其返回值,从而更好地应用它。

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。
10年以上业内强师集结,手把手带你蜕变精英
请您保持通讯畅通,专属学习老师24小时内将与您1V1沟通
免费领取
今日已有369人领取成功
刘同学 138****2860 刚刚成功领取
王同学 131****2015 刚刚成功领取
张同学 133****4652 刚刚成功领取
李同学 135****8607 刚刚成功领取
杨同学 132****5667 刚刚成功领取
岳同学 134****6652 刚刚成功领取
梁同学 157****2950 刚刚成功领取
刘同学 189****1015 刚刚成功领取
张同学 155****4678 刚刚成功领取
邹同学 139****2907 刚刚成功领取
董同学 138****2867 刚刚成功领取
周同学 136****3602 刚刚成功领取
相关推荐HOT