linux c/c++網路程式設計之—select模型
阿新 • • 發佈:2019-02-05
1.select 模型是一個比較傳統的非同步IO模型,我們知道的著名的apache就是基於select模型,而我之前工作過的搜狐暢遊的天龍八部,還有幾款遊戲都是基於select模型。
對於select模型,大多都是說他的缺點,實際上我的觀點有點不一樣,select模型的跨平臺性是比較好的,開發也比較簡單,只有當個程序連線數的限制,以及其效能隨著連線數增長下降的問題,實際上都得根據專案的實際情況而定的。在內部分散式通訊中,幾乎所有的連線都是活躍的情況下,select模型並不比epoll的效能差,只是在一些應用中大部分連線都不活躍的情況,epoll的使用效果要高,可以使單臺伺服器的承載量大大增加,實際上游戲伺服器中玩家絕大部發是活躍的,因此實際效能也還不錯。
下面是我自己寫的一個簡單的select模型的demo,其中要注意兩個地方,估計寫過select的同學很多都遇到類似的問題,一個是超時的變數實際上每次select後需要重新賦值,否則可能出現一隻超時的情況, 二就是fd_set 每次select後,不活躍的會清零,需要一個備份的。再個就是儲存客戶端socket需要一個數組,佇列,或者其他資料結構都可以,要注意增加,清除的問題。
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<netdb.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<netdb.h> #include<sys/time.h> #include<string.h> #include<sys/select.h> #include<pthread.h> using namespace std; int max_fd(int a[], int n) { int max = 0; for(int i = 0; i < n; i++) { if(max < a[i]) { max = a[i]; } } return max; } int main(int argc, char*argv[]) { int port = 0; int N = 0; if (argc != 3) { cout<<"command error"<<endl; exit(-1); } port = atoi(argv[1]); N = atoi(argv[2]); if(N > FD_SETSIZE) { N = FD_SETSIZE; } int server_sock = 0; struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); if((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { cout<<"create socket error"<<endl; exit(-1); } server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr =htonl(INADDR_ANY); server_addr.sin_port = htons(port); if(bind(server_sock, (struct sockaddr*)&server_addr,sizeof(sockaddr)) == -1) { cout<<"bind error"<<endl; exit(-1); } if(listen(server_sock, 5) == -1) { cout<<"listent error"<<endl; exit(-1); } fd_set fd[2]; FD_ZERO(&fd[0]); FD_SET(server_sock, &fd[0]); int *sock = new int[N]; memset(sock, 0, sizeof(int)*N); sock[0] = server_sock; int count = 0; while(1) { struct timeval tv = {5, 0}; FD_ZERO(&fd[1]); fd[1] = fd[0]; int ret = select(max_fd(sock, N)+1, &fd[1], NULL, NULL, &tv); if(ret < 0) { cout<<"select error"<<endl; } else if(ret == 0) { cout<<"time out"<<endl; } else { if(FD_ISSET(sock[0], &fd[1]) && count < N-1) { struct sockaddr_in client_addr; memset(&client_addr, 0, sizeof(client_addr)); unsigned int len = sizeof(client_addr); int new_sock=accept(sock[0],(struct sockaddr*)&client_addr, &len); if(new_sock == -1) { cout<<"accept error"<<endl; } else { for(int i = 1; i < N; i++) { if(sock[i] == 0) { sock[i] = new_sock; FD_SET(new_sock, &fd[0]); count++; break; } } } } char recvbuf[1024] = {0}; char sendbuf[1024] = {0}; for(int i = 1; i < N; i++) { if(FD_ISSET(sock[i], &fd[1])) { if(recv(sock[i], recvbuf, sizeof(recvbuf), 0) <= 0) { cout<<"recv error"<<endl; FD_CLR(sock[i], &fd[0]); close(sock[i]); sock[i] = 0; count--; continue; } strcpy(sendbuf, recvbuf); if(send(sock[i], sendbuf, sizeof(sendbuf), 0) <= 0) { cout<<"send error"<<endl; FD_CLR(sock[i], &fd[0]); close(sock[i]); sock[i] = 0; count--; continue; } } }//end for } }//end while return 0; }