int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, timeval *tv);
参数从前至后:最大文件描述符+1, 读文件描述符集合,写文件描述符集合,异常文件描述符集合,等待超时时间
fd_set set;
FD_ZERO(&set); /*将set清零使集合中不含任何fd*/
FD_SET(fd, &set); /*将fd加入set集合*/
FD_CLR(fd, &set); /*将fd从set集合中清除*/
FD_ISSET(fd, &set); /*测试fd是否在set集合中*/
当使用select时,1个最常见的编程错误是:忘了对最大描述字加1
忘了描述字集是值-结果参数,select返回时会将那些没准备好的bit置为0,所以如果要再次select时,一定要重新用FD_SET设置你感兴趣的描述字的对应bit
忘记重新填写timeout的值
server.c代码如下:
#include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <stdio.h> #include <netinet/in.h> #include <pthread.h> #include <stdlib.h> #include <errno.h> #include <sys/select.h> ssize_t readn(int fd, void *buf, size_t count); ssize_t writen(int fd, const void *buf, size_t count); ssize_t readline(int fd, void *buf, int size); int init_fdset(fd_set *set, int listen_socketfd, int connect_socketfd[],int size, int *maxfd); int deal_listen_socket(int listen_socketfd, int connect_socketfd[], int size); int deal_connect_socket(int connect_socketfd[], int index); int open_listen_socket(const char *ipstr, uint16_t port); int main() { int ret = -1; char recv_buf[100]; int listen_socketfd = -1; int connect_socketfd[100]; int temp_fd = -1; int maxfd = -1; int *pcnn_sd = NULL; fd_set rset; int i = 0; for (i=0; i<sizeof(connect_socketfd)/sizeof(int); i++) { connect_socketfd[i] = -1; } listen_socketfd = open_listen_socket("127.0.0.1", 4321); if (listen_socketfd < 0) { printf("open_listen_socket err\n"); return -1; } while (1) { init_fdset(&rset, listen_socketfd, connect_socketfd, sizeof(connect_socketfd)/sizeof(int), &maxfd); ret = select(maxfd+1, &rset, NULL, NULL, NULL); if (ret < 0) { perror("select err"); return -1; } if (FD_ISSET(listen_socketfd, &rset)) { deal_listen_socket(listen_socketfd, connect_socketfd, sizeof(connect_socketfd)/sizeof(int)); } for (i=0; i<sizeof(connect_socketfd)/sizeof(int); i++) { if (connect_socketfd[i] > 0) { if (FD_ISSET(connect_socketfd[i], &rset)) { deal_connect_socket(connect_socketfd, i); } } } } close(listen_socketfd); return 0; } int init_fdset(fd_set *set, int listen_socketfd, int connect_socketfd[], int size, int *maxfd) { int i = 0; FD_ZERO(set); FD_SET(listen_socketfd, set); *maxfd = listen_socketfd; for (i=0; i<size; i++) { if (connect_socketfd[i] >= 0) { FD_SET(connect_socketfd[i], set); if (connect_socketfd[i] > *maxfd) { *maxfd = connect_socketfd[i]; } } } return 0; } int deal_listen_socket(int listen_socketfd, int connect_socketfd[], int size) { int temp_fd = -1; int i = -1; struct sockaddr_in client_addr; socklen_t client_addr_len = 0; client_addr_len = sizeof(struct sockaddr_in); temp_fd = accept(listen_socketfd, (struct sockaddr *)&client_addr, &client_addr_len); if (temp_fd < 0) { perror("accept err"); return -1; } for (i=0; i<size; i++) { if (connect_socketfd[i] < 0) { connect_socketfd[i] = temp_fd; break; } } return 0; } int deal_connect_socket(int connect_socketfd[], int index) { char recv_buf[100]; int ret = -1; memset(recv_buf, 0, sizeof(recv_buf)); ret = readline(connect_socketfd[index], recv_buf, sizeof(recv_buf)); if (ret < 0) { perror("readline err"); } else if (ret == 0) { printf("client close\n"); close(connect_socketfd[index]); connect_socketfd[index] = -1; } else { ret = writen(connect_socketfd[index], recv_buf, ret); if (ret < 0) { perror("writen err"); close(connect_socketfd[index]); connect_socketfd[index] = -1; } } return 0; } int open_listen_socket(const char *ipstr, uint16_t port) { int ret = -1; int listen_sd = -1; struct sockaddr_in server_addr; listen_sd = socket(AF_INET, SOCK_STREAM, 0); if (listen_sd < 0) { perror("socket err"); return -1; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); ret = inet_pton(AF_INET, ipstr, &(server_addr.sin_addr.s_addr)); if (ret < 0) { perror("inet_pton err"); close(listen_sd); return -1; } ret = bind(listen_sd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)); if (ret < 0) { perror("bind err"); close(listen_sd); return -1; } ret = listen(listen_sd, 6); if (ret < 0) { perror("listen err"); close(listen_sd); return -1; } return listen_sd; } ssize_t readn(int fd, void *buf, size_t count) { char *strtmp = NULL; ssize_t reval = 0; ssize_t realcount = 0; strtmp = (char *)buf; while (count > 0) { reval = read(fd, strtmp, count); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval > 0) { count -= reval; strtmp += reval; realcount += reval; continue; } else { break; } } return realcount; } ssize_t writen(int fd, const void *buf, size_t count) { char *strtmp = NULL; ssize_t reval = 0; ssize_t realcount = 0; strtmp = (char *)buf; while (count > 0) { reval = write(fd, strtmp, count); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval > 0) { count -= reval; strtmp += reval; realcount += reval; continue; } else { break; } } return realcount; } ssize_t readline(int fd, void *buf, int size) { char *strtmp = NULL; ssize_t reval; ssize_t realcount=0; strtmp = (char *)buf; while(size>1) { reval = read(fd, strtmp, 1); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval == 0) { break; } else { realcount++; size--; if (*strtmp++ == '\n') { break; } } } *strtmp='\0'; return realcount; }
#include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <stdio.h> #include <netinet/in.h> #include <errno.h> #include <stdlib.h> #include <sys/select.h> ssize_t readn(int fd, void *buf, size_t count); ssize_t writen(int fd, const void *buf, size_t count); ssize_t readline(int fd, void *buf, int size); void read_stdin(int socketfd); void read_socket(int socketfd); int open_socket(const char *ipstr, uint16_t port); int main() { int socketfd = -1; int *psocket = NULL; int ret = -1; fd_set rset; socketfd = open_socket("127.0.0.1", 4321); if (socketfd < 0) { return -1; } printf("sizeof(fd_set)*8 = %d\n", sizeof(fd_set)*8); while (1) { FD_ZERO(&rset); FD_SET(0, &rset); FD_SET(socketfd, &rset); ret = select(socketfd+1, &rset, NULL, NULL, NULL); if (ret < 0) { perror("select err"); return -1; } if (FD_ISSET(0, &rset)) { read_stdin(socketfd); } if (FD_ISSET(socketfd, &rset)) { read_socket(socketfd); } } return 0; } void read_stdin(int socketfd) { int ret = -1; char send_buf[100]; memset(send_buf, 0, sizeof(send_buf)); ret = readline(0, send_buf, sizeof(send_buf)); if (ret < 0) { perror("readline 0 err"); return; } else if (ret == 0) { printf("readline ret = 0\n"); shutdown(socketfd, SHUT_WR); return; } else { ret = writen(socketfd, send_buf, strlen(send_buf)); if (ret < 0) { perror("writen err"); return; } } } void read_socket(int socketfd) { char recv_buf[100]; int ret = -1; memset(recv_buf, 0, sizeof(recv_buf)); ret = readline(socketfd, recv_buf, sizeof(recv_buf)); if (ret < 0) { perror("read sd err"); return; } else if (ret == 0) { printf("sever close\n"); close(socketfd); exit(0); } else { printf("recv_buf = %s\n", recv_buf); } } int open_socket(const char *ipstr, uint16_t port) { int ret = -1; int socketfd = -1; struct sockaddr_in server_addr; socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd < 0) { perror("socket err"); return -1; } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); ret = inet_pton(AF_INET, ipstr, &(server_addr.sin_addr.s_addr)); if (ret < 0) { perror("inet_pton err"); close(socketfd); return -1; } ret = connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)); if (ret < 0) { perror("connect err"); close(socketfd); return -1; } return socketfd; } ssize_t readn(int fd, void *buf, size_t count) { char *strtmp = NULL; ssize_t reval = 0; ssize_t realcount = 0; strtmp = (char *)buf; while (count > 0) { reval = read(fd, strtmp, count); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval > 0) { count -= reval; strtmp += reval; realcount += reval; continue; } else { break; } } return realcount; } ssize_t writen(int fd, const void *buf, size_t count) { char *strtmp = NULL; ssize_t reval = 0; ssize_t realcount = 0; strtmp = (char *)buf; while (count > 0) { reval = write(fd, strtmp, count); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval > 0) { count -= reval; strtmp += reval; realcount += reval; continue; } else { break; } } return realcount; } ssize_t readline(int fd, void *buf, int size) { char *strtmp = NULL; ssize_t reval; ssize_t realcount=0; strtmp = (char *)buf; while(size>1) { reval = read(fd, strtmp, 1); if (reval < 0) { if (errno == EINTR) { continue; } else { return -1; } } else if (reval == 0) { break; } else { realcount++; size--; if (*strtmp == '\n' || *strtmp == '\r') { break; } strtmp++; } } strtmp++; //žÃÐÐŽø'\n' or '\r' *strtmp='\0'; return realcount; }