linux select函数怎么用
时间: 2024-05-10 20:17:05 浏览: 7
`select()` 函数是用来监视文件描述符的状态,可以同时监视多个文件描述符,当文件描述符状态改变时,它可以通知程序进行相应的操作。在 Linux 中,`select()` 函数的原型是:
```
#include <sys/select.h>
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 结构体,用于设置超时时间。
`fd_set` 是一个文件描述符集合,可以通过以下宏定义进行设置和操作:
- `FD_ZERO(fd_set *set)`:清空文件描述符集合;
- `FD_SET(int fd, fd_set *set)`:将文件描述符 fd 加入到集合 set 中;
- `FD_CLR(int fd, fd_set *set)`:将文件描述符 fd 从集合 set 中删除;
- `FD_ISSET(int fd, fd_set *set)`:检测文件描述符 fd 是否在集合 set 中。
`select()` 函数的返回值表示有多少个文件描述符已经准备好,可以进行相应的操作。如果返回值为 0,表示超时;如果返回值为 -1,表示出错,可以使用 `perror()` 函数打印错误信息。
下面是一个简单的使用 `select()` 函数实现 TCP 服务器的例子:
```c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 80
#define SERV_PORT 8000
int main()
{
int listenfd, connfd, sockfd;
int maxfd, maxi, i, nready;
ssize_t n;
char buf[MAXLINE];
socklen_t clilen;
struct sockaddr_in servaddr, cliaddr;
fd_set rset, allset;
int client[FD_SETSIZE];
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 20);
maxfd = listenfd;
maxi = -1;
for (i = 0; i < FD_SETSIZE; ++i)
client[i] = -1;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
while (1) {
rset = allset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if (nready < 0) {
perror("select error");
exit(1);
}
if (FD_ISSET(listenfd, &rset)) { /* new client */
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
for (i = 0; i < FD_SETSIZE; ++i) {
if (client[i] < 0) {
client[i] = connfd;
break;
}
}
if (i == FD_SETSIZE) {
fprintf(stderr, "too many clients\n");
exit(1);
}
FD_SET(connfd, &allset);
if (connfd > maxfd)
maxfd = connfd;
if (i > maxi)
maxi = i;
if (--nready <= 0)
continue;
}
for (i = 0; i <= maxi; ++i) {
if ((sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
if ((n = read(sockfd, buf, MAXLINE)) == 0) { /* client closed */
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
} else { /* echo back */
write(sockfd, buf, n);
}
if (--nready <= 0)
break;
}
}
}
return 0;
}
```
在本例中,使用 `select()` 函数同时监视 `listenfd` 和所有已连接的客户端套接字。当 `listenfd` 准备好时,表示有新客户端连接,程序会接收连接请求并将新的套接字添加到文件描述符集合中。当某个客户端套接字准备好时,程序会从该套接字读取数据,并将数据回显到客户端。