多路转接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; }
时间: 2024-12-24 05:04:08