select函数简解:
selct 称之为多路复用IO,使用它可以让程序阻塞在select上,而非实际IO函数上.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds: fd_set描述符集中 {最大描述符+1}
readfds: 读描述符集
writefds: 写描述符集
exceptfds: 异常描述符集
timeout: 超时时间,1)当timeout为NULL时,select将阻塞到有读或写或异常描述符就绪才返回。
2)当timeout中tv_sec==0且tv_usec==0时,表示不等待,扫描一次马上返回。
3)当timeout中tv_sec!=0且tv_usec!=0时,表示在指定时间内没有就绪描述符就返回。函数返回0
注意:
1)正常情况下返回就绪描述符个数!
2)同时会将未就绪的描述符置零,所以select每次返回后我们都应将需用监听的描述符重新添加到描述符集中。
3)为了可移植,当设置了超时时间时也应当从新赋值。
4)使用select函数尽量不要与非系统IO混用
以下是对描述符集操作的函数:
void FD_CLR(int fd, fd_set *set);
从描述符集set中清除描述符fd
int FD_ISSET(int fd, fd_set *set);
判断描述符fd 是否在描述符集set中,是,返回非0;否,返回0
void FD_SET(int fd, fd_set *set);
将描述符fd 添加到描述符集set中
void FD_ZERO(fd_set *set);
对描述符集进行清零,当我们新定义一个描述集时,最好使用此函数进行清零,
简单的服务器回射程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#define SERV_PORT 10086
typedef struct sockaddr SA;
int main(void)
{
int listenfd, connfd;
struct sockaddr_in cliaddr, servaddr;
socklen_t clientlen;
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
err_quit("socket error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listenfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {
err_quit("bind error");
}
if (listen(listenfd, 5) < 0) {
err_quit("listen error");
}
fd_set rfds, allfd;
int maxfd, maxi = -1;
int client[FD_SETSIZE];
int nready;
int i, nread;
int sockfd;
char buf[MAXLINE];
FD_ZERO(&allfd);
FD_SET(listenfd, &allfd);
maxfd = listenfd;
for (i=0; i1;
}
for ( ; ; ) {
rfds = allfd;
nready = select(maxfd+1, &rfds, NULL, NULL, NULL);
if (nready < 0) {
err_quit("select error");
}
if (FD_ISSET(listenfd, &rfds)) {
#ifdef DEBUG
printf("have descriptor....\n");
#endif
clientlen = sizeof(cliaddr);
connfd = accept(listenfd, (SA *)&cliaddr, &clientlen);
if (connfd < 0) {
err_quit("accept error");
}
for (i=0; iif (client[i] < 0) {
client[i] = connfd;
break;
}
}
if (i == FD_SETSIZE) {
err_quit("too many clients");
}
FD_SET(connfd, &allfd);
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, &rfds)) {
#ifdef DEBUG
printf("fd: %d\n", sockfd);
#endif
if ((nread = read(sockfd, buf, MAXLINE)) == 0) {
close(sockfd);
FD_CLR(sockfd, &allfd);
client[i] = -1;
} else {
if (write(sockfd, buf, nread) != nread) {
err_msg("fail to write...");
}
}
if (--nready <= 0) {
continue;
}
}
}
}
return EXIT_SUCCESS;
}