多路复用I/O: socket编程之select(),poll(),epoll()
代码:
client.c
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <netinet/in.h> 8 #include <sys/socket.h> 9 #include <sys/select.h> 10 #include <arpa/inet.h> 11 #include <assert.h> 12 #define maxn 1100 13 #define IP "127.0.0.1" 14 #define PORT 45178 15 #define MAXLINE 1024 16 #define LISTENQ 5 17 #define SIZE 10 18 #define BACKLOG 2 19 int main() 20 { 21 int sockfd; 22 if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) 23 { 24 printf("socket error! "); 25 exit(1); 26 } 27 struct sockaddr_in server; 28 bzero(&server,sizeof(server)); 29 server.sin_family = AF_INET; 30 server.sin_port = htons(PORT); 31 inet_pton(AF_INET,IP,&server.sin_addr); 32 char buf[maxn]; 33 int connfd; 34 connfd = connect(sockfd,(struct sockaddr*)&server,sizeof(server)); 35 if(connfd < 0) 36 { 37 printf("connect failure! "); 38 return -1; 39 } 40 printf("client send to server "); 41 printf("please input something "); 42 scanf("%s",buf); 43 write(sockfd,buf,maxn); 44 char recvbuf[maxn]; 45 char sendbuf[maxn]; 46 fd_set readfd; 47 int maxnum = 0; 48 struct timeval T_time; 49 int n; 50 int sel_fd; 51 while(1) 52 { 53 FD_ZERO(&readfd); 54 FD_SET(sockfd,&readfd); 55 maxnum = sockfd; 56 T_time.tv_sec = 2; 57 T_time.tv_usec = 0; 58 sel_fd = select(maxnum + 1,&readfd,NULL,NULL,&T_time); 59 if(sel_fd < 0) 60 { 61 continue; 62 } 63 else if(sel_fd == -1) 64 { 65 printf("select error! "); 66 return; 67 } 68 if(FD_ISSET(sockfd,&readfd)) 69 { 70 n = read(sockfd,recvbuf,maxn); 71 if(n <= 0) 72 { 73 printf("server is closed! "); 74 close(sockfd); 75 FD_CLR(sockfd,&readfd); 76 return; 77 } 78 printf("recv message is %s ", recvbuf); 79 sleep(5); 80 write(sockfd,buf,strlen(buf) + 1); 81 } 82 } 83 close(sockfd); 84 return 0; 85 }
server.c
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <netinet/in.h> 8 #include <sys/socket.h> 9 #include <sys/select.h> 10 #include <arpa/inet.h> 11 #include <assert.h> 12 #define maxn 1100 13 #define PORT 45178 14 #define IP "127.0.0.1" 15 #define MAXLINE 1024 16 #define LISTENQ 5 17 #define SIZE 10 18 #define BACKLOG 2 19 typedef struct server_context_st 20 { 21 int cli_num; /*客户端个数*/ 22 int cli_fds[SIZE]; /*客户端的个数*/ 23 fd_set allfds; /*句柄集合*/ 24 int maxfd; /*句柄最大值*/ 25 } server_context_st; 26 27 static int init(); 28 static void deal_maxfd(int sockfd); 29 static int accept_client(int sockfd); 30 static void recv_client_msg(fd_set *readfd); 31 static void submit_client_msg(int temp,char buf[]); 32 static server_context_st *server_client = NULL; 33 int Max(int a,int b); 34 int Max(int a,int b) 35 { 36 return a>b?a:b; 37 } 38 static int server_init() 39 { 40 server_client = (server_context_st *)malloc(sizeof(server_context_st)); 41 if(server_client == NULL) 42 { 43 return -1; 44 } 45 memset(server_client,0,sizeof(server_context_st)); 46 int i=0; 47 for(;i<SIZE;i++) 48 { 49 server_client->cli_fds[i] = -1; 50 } 51 return 0; 52 } 53 static int init() 54 { 55 56 int sockfd; 57 if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) 58 { 59 printf("socket error! "); 60 exit(1); 61 } 62 int listenfd; 63 struct sockaddr_in server; 64 bzero(&server,sizeof(server)); 65 server.sin_family = AF_INET; 66 server.sin_port = htons(PORT); 67 inet_pton(AF_INET,IP,&server.sin_addr); 68 if(bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr)) == -1) 69 { 70 perror("bind error:"); 71 return -1; 72 } 73 listen(sockfd,BACKLOG); 74 return sockfd; 75 } 76 static void deal_maxfd(int sockfd) 77 { 78 fd_set *readfd = &server_client->allfds; 79 int sel_fd = 0; 80 int clifd = -1; 81 struct timeval T_time; 82 while(1) 83 { 84 FD_ZERO(readfd); 85 FD_SET(sockfd,readfd); 86 server_client->maxfd = sockfd; 87 T_time.tv_sec = 30; 88 T_time.tv_usec = 0; 89 90 int i; 91 for(i=0;i<server_client->cli_num;i++) 92 { 93 clifd = server_client->cli_fds[i]; 94 FD_SET(clifd,readfd); 95 server_client->maxfd = Max(clifd,server_client->maxfd); 96 } 97 //retval = select(s_srv_ctx->maxfd + 1, readfds, NULL, NULL, &tv); 98 sel_fd = select(server_client->maxfd+1,readfd,NULL,NULL,&T_time); 99 if(sel_fd == 0) 100 { 101 printf("time out! "); 102 continue; 103 } 104 else if(sel_fd == -1) 105 { 106 printf("something error! "); 107 return ; 108 } 109 if(FD_ISSET(sockfd,readfd)) 110 { 111 /*监听客户端请求*/ 112 accept_client(sockfd); 113 } 114 else 115 { 116 /*接受处理客户端消息*/ 117 recv_client_msg(readfd); 118 } 119 } 120 } 121 static int accept_client(int sockfd) 122 { 123 struct sockaddr_in server_c; 124 socklen_t len; 125 len = sizeof (server_c); 126 int afd = -1; 127 Loop: 128 printf("waiting ............................ "); 129 afd = accept(sockfd,(struct sockaddr*)&server_c,&len); 130 if(afd == -1) 131 { 132 if(errno == EINTR) 133 { 134 goto Loop; 135 } 136 else 137 { 138 fprintf(stderr, "accept fail,error:%s ", strerror(errno)); 139 return -1; 140 } 141 } 142 printf("accept successful! "); 143 int i=0; 144 for(i=0;i<SIZE;i++) 145 { 146 if(server_client->cli_fds[i] < 0) 147 { 148 server_client->cli_fds[i] = afd; 149 server_client->cli_num ++; 150 break; 151 } 152 } 153 if(i == SIZE) 154 { 155 printf("too many client to accept! "); 156 return -1; 157 } 158 } 159 static void recv_client_msg(fd_set *readfd) 160 { 161 int i=0; 162 int temp; 163 char buf[maxn]; 164 for(i=0;i<server_client->cli_num;i++) 165 { 166 temp = server_client->cli_fds[i]; 167 if(temp < 0) 168 { 169 continue; 170 } 171 if(FD_ISSET(temp,readfd)) 172 { 173 int n = read(temp,buf,maxn); 174 if(n <= 0) 175 { 176 FD_CLR(temp,&server_client->allfds); 177 close(temp); 178 server_client->cli_fds[i] = -1; 179 continue; 180 } 181 submit_client_msg(temp,buf); 182 } 183 } 184 } 185 static void submit_client_msg(int temp,char buf[]) 186 { 187 assert(buf); 188 printf("receive message is %s ",buf); 189 write(temp,buf,strlen(buf)+1); 190 return ; 191 } 192 int main() 193 { 194 if(server_init() == -1) 195 { 196 printf("init error "); 197 return -1; 198 } 199 int sockfd; 200 sockfd = init(); 201 deal_maxfd(sockfd); 202 close(sockfd); 203 return 0; 204 }
结果: