面试题答案
一键面试select函数参数构成及其含义
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- nfds:监控的文件描述符集里最大文件描述符加1。
- readfds:指向fd_set结构的指针,用于检查可读性的文件描述符集合。
- writefds:指向fd_set结构的指针,用于检查可写性的文件描述符集合。
- exceptfds:指向fd_set结构的指针,用于检查是否有异常条件待处理的文件描述符集合。
- timeout:指向
struct timeval
结构的指针,用于设置select函数的超时时间。如果为NULL
,表示select函数将一直阻塞,直到有事件发生;如果timeval
结构体中的tv_sec
和tv_usec
都为0,则select函数不阻塞,立即返回。
示例代码框架
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#define PORT 8080
#define MAX_CLIENTS 10
int main(int argc, char const *argv[]) {
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置套接字选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// 绑定套接字
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听套接字
if (listen(server_fd, MAX_CLIENTS) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
fd_set read_fds;
fd_set tmp_fds;
FD_ZERO(&read_fds);
FD_ZERO(&tmp_fds);
// 将服务器套接字添加到读集合中
FD_SET(server_fd, &read_fds);
int activity, max_sd;
max_sd = server_fd;
while (1) {
tmp_fds = read_fds;
activity = select(max_sd + 1, &tmp_fds, NULL, NULL, NULL);
if (activity < 0) {
perror("select error");
} else if (activity > 0) {
if (FD_ISSET(server_fd, &tmp_fds)) {
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
continue;
}
FD_SET(new_socket, &read_fds);
if (new_socket > max_sd) {
max_sd = new_socket;
}
}
for (int i = 0; i <= max_sd; i++) {
if (FD_ISSET(i, &tmp_fds)) {
valread = read(i, buffer, 1024);
if (valread == 0) {
close(i);
FD_CLR(i, &read_fds);
} else {
buffer[valread] = '\0';
printf("Message received: %s\n", buffer);
}
}
}
}
}
close(server_fd);
return 0;
}