高性能网络编程 - select系统调用
Posted gccbuaa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高性能网络编程 - select系统调用相关的知识,希望对你有一定的参考价值。
IO复用使得程序可以同一时候监听多个文件描写叙述符,比方client须要同一时候处理用户输入和网络连接,server端须要同一时候处理监听套接字和连接套接字,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; }
參考:《高性能server编程》和《UNP》
以上是关于高性能网络编程 - select系统调用的主要内容,如果未能解决你的问题,请参考以下文章
如何用 kevent() 替换 select() 以获得更高的性能?
JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段