多路轉接I/O服務器中的一種:select服務器,該模型的服務器是將文件描述符放入隊列中保存並監聽,以輪詢的機制去監聽這些文件描述符,當相對應的文件描述符有讀請求、寫情況或異常發生時,對應的位將發生變化。select模型需要對所有監聽的套接字實行輪詢監聽處理,當需要監聽的套接字過多時,就可能出現響應不及時等問題,從而降低了服務器性能。
下面是服務器的實現(服務器將客戶端發送過來的數據全部轉換爲大寫)
#include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <errno.h> #include <string.h> #include <sys/select.h> int main(int argc, char const *argv[]) { //創建套接字 int listen_fd=socket(AF_INET,SOCK_STREAM,0); if(-1==listen_fd) { perror("socket"); return ; } //構造地址結構 struct sockaddr_in seraddr; memset(&seraddr,0,sizeof(seraddr)); seraddr.sin_family=AF_INET; seraddr.sin_port=htons(1234); seraddr.sin_addr.s_addr=inet_addr("192.168.1.30"); //將地址結構和套接字綁定 if(bind(listen_fd,(struct sockaddr*)&seraddr,sizeof(seraddr))==-1) { perror("bind"); return ; } //設置連接隊列數目 if(listen(listen_fd,10)==-1) { perror("listen"); return ; } int maxfd=listen_fd; fd_set readset; struct timeval ts; ts.tv_sec=1; int clifd[128]; int i,index=0; for(i=0;i<128;i++) { clifd[i]=-1; } while(1) { FD_ZERO(&readset);//清除 FD_SET(listen_fd,&readset);//將listen_fd放到監聽隊列 for(i=0;i<index;i++) { FD_SET(clifd[i],&readset); } //監聽 int ret=select(maxfd+1,&readset,NULL,NULL,&ts); if(ret==-1) { perror("select"); return ; } //有請求發生 if(ret>0) { //新的連接 if(FD_ISSET(listen_fd,&readset)) { struct sockaddr_in cliaddr; memset(&cliaddr,0,sizeof(cliaddr)); int cli_size=sizeof(cliaddr); int fd=accept(listen_fd,(struct sockaddr*)&cliaddr,&cli_size); if(-1==fd) { perror("accept"); return ; } clifd[index]=fd; if(clifd[index]>maxfd) { maxfd=clifd[index]; } index++; printf("index:%d\n",index); } for(i=0;i<index;i++) { //數據處理 if(FD_ISSET(clifd[i],&readset)) { char buf[1024]; int j=0; int len=read(clifd[i],buf,sizeof(buf)-1); buf[len]='\0'; printf("%s\n",buf); while(buf[j]!='\0') { if(buf[j]>='a' && buf[j]<='z') { buf[j] -= 0x20; } j++; } write(clifd[i],buf,strlen(buf)); } } } } return 0; }