首页 > 代码库 > 高性能网络编程 - select系统调用
高性能网络编程 - select系统调用
IO复用使得程序能够同时监听多个文件描述符,比如客户端需要同时处理用户输入和网络连接,服务器端需要同时处理监听套接字和连接套接字,select系统调用可以使得我们监听自己感兴趣描述符,可读,可写,异常等事件。select能处理的异常只有带外数据。能同时处理描述符的数量受限于FD_SETSIZE的大小(一般1024)。下面这个程序展示了它的一般用法。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <libgen.h> //basename #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <assert.h> #include <errno.h> int main(int argc, char *argv[]){ int i, maxi; char buf[1024]; fd_set read_fds, all_read_fds; fd_set exception_fds, all_exception_fds; int nready, connectfd[FD_SETSIZE]; int connfd,sockfd,maxfd; struct sockaddr_in client_address; socklen_t client_addrlen = sizeof(client_address); if(argc <= 2){ printf("usage: %s ip_address port_number\n", basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); int ret = 0; struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET, ip, &address.sin_addr); address.sin_port = htons(port); int listenfd = socket(AF_INET, SOCK_STREAM, 0); assert(listenfd >= 0); ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address)); assert(ret != -1); ret = listen(listenfd, 5); assert(ret != -1); maxfd = listenfd; maxi = -1; for(i= 0; i < FD_SETSIZE; i++) connectfd[i] = -1; FD_ZERO(&all_read_fds); FD_ZERO(&all_exception_fds); FD_SET(listenfd, &all_read_fds); //do not care about the OOB of listen socket while(1){ read_fds = all_read_fds; exception_fds = all_exception_fds; memset(buf, 0, sizeof(buf)); nready = select(maxfd + 1, &read_fds, NULL, &exception_fds, NULL); //new client connection coming if(FD_ISSET(listenfd, &read_fds)){ connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_addrlen); if(connfd < 0){ perror("accept failed\n"); exit(-1); } for(i=0; i < FD_SETSIZE; i++) if(connectfd[i] < 0){ connectfd[i] = connfd; break; } if( i == FD_SETSIZE){ printf("too many clients..\n"); exit(-1); } // add new descriptor to the read set and exception set FD_SET(connfd, &all_read_fds); FD_SET(connfd, &all_exception_fds); if(connfd > maxfd) maxfd = connfd; if(i > maxi) maxi = i;// update the max index in connectfd[] //we complete the listen socktet processing if(--nready <= 0) continue; } for(i = 0; i <= maxi; i++){ //check all the connected clients for data if((sockfd = connectfd[i]) < 0) continue; if(FD_ISSET(sockfd, &read_fds)){ ret = recv(sockfd, buf, sizeof(buf) - 1, 0); if(ret <= 0) break;//connection closed // process logic printf("get %d bytes of normal data:%s\n", ret, buf); //we complete the listen socktet processing if(--nready <= 0) continue; } for(i = 0; i <= maxi; i++){ //check all the connected clients for data if((sockfd = connectfd[i]) < 0) continue; if(FD_ISSET(sockfd, &read_fds)){ ret = recv(sockfd, buf, sizeof(buf) - 1, 0); if(ret <= 0) break;//connection closed // process logic printf("get %d bytes of normal data:%s\n", ret, buf); }else if(FD_ISSET(sockfd, &exception_fds)){ //handle exceptions //get out of band data ret = recv(connfd, buf, sizeof(buf) - 1, MSG_OOB); if(ret <= 0) break; printf("get %d bytes of OOB data: %s", ret, buf); } FD_CLR(sockfd, &all_read_fds); FD_CLR(sockfd, &all_exception_fds); //after we deal with this client close(sockfd); if(--nready <= 0) break; } } close(listenfd); return 0; }
参考:《高性能服务器编程》和《UNP》
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。