Andy Niu Help
1.0.0.0
|
变量 | |
IO多路复用__总结 | |
IO多路复用__select | |
IO多路复用__poll | |
IO多路复用__epoll | |
详细描述
变量说明
IO多路复用__epoll |
1、server.cpp #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/epoll.h> #include <unistd.h> #include <sys/types.h> #define IPADDRESS "127.0.0.1" #define PORT 8787 #define MAXSIZE 1024 #define LISTENQ 5 #define FDSIZE 1000 #define EPOLLEVENTS 100 //函数声明 //创建套接字并进行绑定 static int socket_bind(const char* ip,int port); //IO多路复用epoll static void do_epoll(int listenfd); //事件处理函数 static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf); //处理接收到的连接 static void handle_accpet(int epollfd,int listenfd); //读处理 static void do_read(int epollfd,int fd,char *buf); //写处理 static void do_write(int epollfd,int fd,char *buf); //添加事件 static void add_event(int epollfd,int fd,int state); //修改事件 static void modify_event(int epollfd,int fd,int state); //删除事件 static void delete_event(int epollfd,int fd,int state); int main(int argc,char *argv[]) { int listenfd; listenfd = socket_bind(IPADDRESS,PORT); listen(listenfd,LISTENQ); do_epoll(listenfd); return 0; } static int socket_bind(const char* ip,int port) { int listenfd; struct sockaddr_in servaddr; listenfd = socket(AF_INET,SOCK_STREAM,0); if (listenfd == -1) { perror("socket error:"); exit(1); } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET,ip,&servaddr.sin_addr); servaddr.sin_port = htons(port); if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1) { perror("bind error: "); exit(1); } return listenfd; } static void do_epoll(int listenfd) { int epollfd; struct epoll_event events[EPOLLEVENTS]; int ret; char buf[MAXSIZE]; memset(buf,0,MAXSIZE); //创建一个描述符 epollfd = epoll_create(FDSIZE); //添加监听描述符事件 add_event(epollfd,listenfd,EPOLLIN); for ( ; ; ) { //获取已经准备好的描述符事件 ret = epoll_wait(epollfd,events,EPOLLEVENTS,-1); handle_events(epollfd,events,ret,listenfd,buf); } close(epollfd); } static void handle_events(int epollfd,struct epoll_event *events,int num,int listenfd,char *buf) { int i; int fd; //进行选好遍历 for (i = 0;i < num;i++) { fd = events[i].data.fd; //根据描述符的类型和事件类型进行处理 if ((fd == listenfd) &&(events[i].events & EPOLLIN)) handle_accpet(epollfd,listenfd); else if (events[i].events & EPOLLIN) do_read(epollfd,fd,buf); else if (events[i].events & EPOLLOUT) do_write(epollfd,fd,buf); } } static void handle_accpet(int epollfd,int listenfd) { int clifd; struct sockaddr_in cliaddr; socklen_t cliaddrlen; clifd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen); if (clifd == -1) perror("accpet error:"); else { // 注意:cliaddr.sin_port的字节逆序,需要转换一下ntohs(cliaddr.sin_port) printf("accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); //添加一个客户描述符和事件 add_event(epollfd,clifd,EPOLLIN); } } static void do_read(int epollfd,int fd,char *buf) { int nread; nread = read(fd,buf,MAXSIZE); if (nread == -1) { perror("read error:"); close(fd); delete_event(epollfd,fd,EPOLLIN); } else if (nread == 0) { fprintf(stderr,"client close.\n"); close(fd); delete_event(epollfd,fd,EPOLLIN); } else { printf("read message is : %s",buf); //修改描述符对应的事件,由读改为写 modify_event(epollfd,fd,EPOLLOUT); } } static void do_write(int epollfd,int fd,char *buf) { int nwrite; nwrite = write(fd,buf,strlen(buf)); if (nwrite == -1) { perror("write error:"); close(fd); delete_event(epollfd,fd,EPOLLOUT); } else modify_event(epollfd,fd,EPOLLIN); memset(buf,0,MAXSIZE); } static void add_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev); } static void delete_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev); } static void modify_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev); } 2、client.cpp #include <netinet/in.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/epoll.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #define MAXSIZE 1024 #define IPADDRESS "127.0.0.1" #define SERV_PORT 8787 #define FDSIZE 1024 #define EPOLLEVENTS 20 static void handle_connection(int sockfd); static void handle_events(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf); static void do_read(int epollfd,int fd,int sockfd,char *buf); static void do_read(int epollfd,int fd,int sockfd,char *buf); static void do_write(int epollfd,int fd,int sockfd,char *buf); static void add_event(int epollfd,int fd,int state); static void delete_event(int epollfd,int fd,int state); static void modify_event(int epollfd,int fd,int state); int main(int argc,char *argv[]) { int sockfd; struct sockaddr_in servaddr; sockfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr); connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); //处理连接 handle_connection(sockfd); close(sockfd); return 0; } static void handle_connection(int sockfd) { int epollfd; struct epoll_event events[EPOLLEVENTS]; char buf[MAXSIZE]; int ret; epollfd = epoll_create(FDSIZE); add_event(epollfd,STDIN_FILENO,EPOLLIN); for ( ; ; ) { ret = epoll_wait(epollfd,events,EPOLLEVENTS,-1); handle_events(epollfd,events,ret,sockfd,buf); } close(epollfd); } static void handle_events(int epollfd,struct epoll_event *events,int num,int sockfd,char *buf) { int fd; int i; for (i = 0;i < num;i++) { fd = events[i].data.fd; if (events[i].events & EPOLLIN) do_read(epollfd,fd,sockfd,buf); else if (events[i].events & EPOLLOUT) do_write(epollfd,fd,sockfd,buf); } } static void do_read(int epollfd,int fd,int sockfd,char *buf) { int nread; nread = read(fd,buf,MAXSIZE); if (nread == -1) { perror("read error:"); close(fd); } else if (nread == 0) { fprintf(stderr,"server close.\n"); close(fd); } else { if (fd == STDIN_FILENO) add_event(epollfd,sockfd,EPOLLOUT); else { delete_event(epollfd,sockfd,EPOLLIN); add_event(epollfd,STDOUT_FILENO,EPOLLOUT); } } } static void do_write(int epollfd,int fd,int sockfd,char *buf) { int nwrite; nwrite = write(fd,buf,strlen(buf)); if (nwrite == -1) { perror("write error:"); close(fd); } else { if (fd == STDOUT_FILENO) delete_event(epollfd,fd,EPOLLOUT); else modify_event(epollfd,fd,EPOLLIN); } memset(buf,0,MAXSIZE); } static void add_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev); } static void delete_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&ev); } static void modify_event(int epollfd,int fd,int state) { struct epoll_event ev; ev.events = state; ev.data.fd = fd; epoll_ctl(epollfd,EPOLL_CTL_MOD,fd,&ev); } 3、运行服务端 [root@localhost Epoll]# g++ -o server server.cpp server.cpp:190:2: warning: no newline at end of file [root@localhost Epoll]# ./server accept a new client: 127.0.0.1:51619 read message is : 123 4、运行客户端 [root@localhost Epoll]# g++ -o client client.cpp client.cpp:143:2: warning: no newline at end of file [root@localhost Epoll]# ./client 123 123
IO多路复用__poll |
1、server.cpp #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <poll.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #define IPADDRESS "127.0.0.1" #define PORT 8787 #define MAXLINE 1024 #define LISTENQ 5 #define OPEN_MAX 1000 #define INFTIM -1 //函数声明 //创建套接字并进行绑定 static int socket_bind(const char* ip,int port); //IO多路复用poll static void do_poll(int listenfd); //处理多个连接 static void handle_connection(struct pollfd *connfds,int num); int main(int argc,char *argv[]) { int listenfd,connfd,sockfd; struct sockaddr_in cliaddr; socklen_t cliaddrlen; listenfd = socket_bind(IPADDRESS,PORT); listen(listenfd,LISTENQ); do_poll(listenfd); return 0; } static int socket_bind(const char* ip,int port) { int listenfd; struct sockaddr_in servaddr; listenfd = socket(AF_INET,SOCK_STREAM,0); if (listenfd == -1) { perror("socket error:"); exit(1); } int reuse = 1; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { return -1; } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET,ip,&servaddr.sin_addr); servaddr.sin_port = htons(port); if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1) { perror("bind error: "); exit(1); } return listenfd; } static void do_poll(int listenfd) { int connfd,sockfd; struct sockaddr_in cliaddr; socklen_t cliaddrlen; struct pollfd clientfds[OPEN_MAX]; int maxi; int i; int nready; //添加监听描述符 clientfds[0].fd = listenfd; clientfds[0].events = POLLIN; //初始化客户连接描述符 for (i = 1;i < OPEN_MAX;i++) clientfds[i].fd = -1; maxi = 0; //循环处理 for ( ; ; ) { //获取可用描述符的个数 nready = poll(clientfds,maxi+1,INFTIM); if (nready == -1) { perror("poll error:"); exit(1); } //测试监听描述符是否准备好 if (clientfds[0].revents & POLLIN) { cliaddrlen = sizeof(cliaddr); //接受新的连接 if ((connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddrlen)) == -1) { if (errno == EINTR) continue; else { perror("accept error:"); exit(1); } } fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); //将新的连接描述符添加到数组中 for (i = 1;i < OPEN_MAX;i++) { if (clientfds[i].fd < 0) { clientfds[i].fd = connfd; break; } } if (i == OPEN_MAX) { fprintf(stderr,"too many clients.\n"); exit(1); } //将新的描述符添加到读描述符集合中 clientfds[i].events = POLLIN; //记录客户连接套接字的个数 maxi = (i > maxi ? i : maxi); if (--nready <= 0) continue; } //处理客户连接 handle_connection(clientfds,maxi); } } static void handle_connection(struct pollfd *connfds,int num) { int i,n; char buf[MAXLINE]; memset(buf,0,MAXLINE); for (i = 1;i <= num;i++) { if (connfds[i].fd < 0) continue; //测试客户描述符是否准备好 if (connfds[i].revents & POLLIN) { //接收客户端发送的信息 n = read(connfds[i].fd,buf,MAXLINE); if (n == 0) { close(connfds[i].fd); connfds[i].fd = -1; continue; } // printf("read msg is: "); write(STDOUT_FILENO,buf,n); //向客户端发送buf write(connfds[i].fd,buf,n); } } } 2、client.cpp #include <netinet/in.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <poll.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <arpa/inet.h> #define MAXLINE 1024 #define IPADDRESS "127.0.0.1" #define SERV_PORT 8787 #define max(a,b) (a > b) ? a : b static void handle_connection(int sockfd); int main(int argc,char *argv[]) { int sockfd; struct sockaddr_in servaddr; sockfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr); connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); //处理连接描述符 handle_connection(sockfd); return 0; } static void handle_connection(int sockfd) { char sendline[MAXLINE],recvline[MAXLINE]; int maxfdp,stdineof; struct pollfd pfds[2]; int n; //添加连接描述符 pfds[0].fd = sockfd; pfds[0].events = POLLIN; //添加标准输入描述符 pfds[1].fd = STDIN_FILENO; pfds[1].events = POLLIN; for (; ;) { poll(pfds,2,-1); if (pfds[0].revents & POLLIN) { n = read(sockfd,recvline,MAXLINE); if (n == 0) { fprintf(stderr,"client: server is closed.\n"); close(sockfd); } write(STDOUT_FILENO,recvline,n); } //测试标准输入是否准备好 if (pfds[1].revents & POLLIN) { n = read(STDIN_FILENO,sendline,MAXLINE); if (n == 0) { shutdown(sockfd,SHUT_WR); continue; } write(sockfd,sendline,n); } } } 3、运行服务端 [root@localhost poll]# ./server accept a new client: 127.0.0.1:54849 abc 4、运行客户端 [root@localhost poll]# ./client abc abc
IO多路复用__select |
1、server.cpp #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/select.h> #include <sys/types.h> #include <unistd.h> #include <assert.h> #define IPADDR "127.0.0.1" #define PORT 8787 #define MAXLINE 1024 #define LISTENQ 5 #define SIZE 10 typedef struct server_context_st { int cli_cnt; /*客户端个数*/ int clifds[SIZE]; /*客户端的个数*/ fd_set allfds; /*句柄集合*/ int maxfd; /*句柄最大值*/ } server_context_st; static server_context_st *s_srv_ctx = NULL; /*=========================================================================== * ==========================================================================*/ static int create_server_proc(const char* ip,int port) { int fd; struct sockaddr_in servaddr; fd = socket(AF_INET, SOCK_STREAM,0); if (fd == -1) { fprintf(stderr, "create socket fail,erron:%d,reason:%s\n", errno, strerror(errno)); return -1; } /*一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。*/ int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { return -1; } bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; // ip和port进行转化 inet_pton(AF_INET,ip,&servaddr.sin_addr); servaddr.sin_port = htons(port); if (bind(fd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1) { perror("bind error: "); return -1; } listen(fd,LISTENQ); return fd; } static int accept_client_proc(int srvfd) { struct sockaddr_in cliaddr; socklen_t cliaddrlen; cliaddrlen = sizeof(cliaddr); int clifd = -1; printf("accpet clint proc is called.\n"); ACCEPT: clifd = accept(srvfd,(struct sockaddr*)&cliaddr,&cliaddrlen); if (clifd == -1) { if (errno == EINTR) { goto ACCEPT; } else { fprintf(stderr, "accept fail,error:%s\n", strerror(errno)); return -1; } } // ip和port进行转化 fprintf(stdout, "accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port)); //将新的连接描述符添加到数组中 int i = 0; for (i = 0; i < SIZE; i++) { if (s_srv_ctx->clifds[i] < 0) { s_srv_ctx->clifds[i] = clifd; s_srv_ctx->cli_cnt++; break; } } if (i == SIZE) { fprintf(stderr,"too many clients.\n"); return -1; } } static int handle_client_msg(int fd, char *buf) { assert(buf); printf("recv buf is :%s\n", buf); write(fd, buf, strlen(buf) +1); return 0; } static void recv_client_msg(fd_set *readfds) { int i = 0, n = 0; int clifd; char buf[MAXLINE] = {0}; for (i = 0;i <= s_srv_ctx->cli_cnt;i++) { clifd = s_srv_ctx->clifds[i]; if (clifd < 0) { continue; } /*判断客户端套接字是否有数据*/ if (FD_ISSET(clifd, readfds)) { //接收客户端发送的信息 n = read(clifd, buf, MAXLINE); if (n <= 0) { /*n==0表示读取完成,客户都关闭套接字*/ FD_CLR(clifd, &s_srv_ctx->allfds); close(clifd); s_srv_ctx->clifds[i] = -1; continue; } handle_client_msg(clifd, buf); } } } static void handle_client_proc(int srvfd) { int clifd = -1; int retval = 0; fd_set *readfds = &s_srv_ctx->allfds; struct timeval tv; int i = 0; while (1) { /*每次调用select前都要重新设置文件描述符和时间,因为事件发生后,文件描述符和时间都被内核修改啦*/ FD_ZERO(readfds); /*添加监听套接字*/ FD_SET(srvfd, readfds); s_srv_ctx->maxfd = srvfd; tv.tv_sec = 30; tv.tv_usec = 0; /*添加客户端套接字*/ for (i = 0; i < s_srv_ctx->cli_cnt; i++) { clifd = s_srv_ctx->clifds[i]; /*去除无效的客户端句柄*/ if (clifd != -1) { FD_SET(clifd, readfds); } s_srv_ctx->maxfd = (clifd > s_srv_ctx->maxfd ? clifd : s_srv_ctx->maxfd); } /*开始轮询接收处理服务端和客户端套接字*/ retval = select(s_srv_ctx->maxfd + 1, readfds, NULL, NULL, &tv); if (retval == -1) { fprintf(stderr, "select error:%s.\n", strerror(errno)); return; } if (retval == 0) { fprintf(stdout, "select is timeout.\n"); continue; } if (FD_ISSET(srvfd, readfds)) { /*监听客户端请求*/ accept_client_proc(srvfd); } else { /*接受处理客户端消息*/ recv_client_msg(readfds); } } } static void server_uninit() { if (s_srv_ctx) { free(s_srv_ctx); s_srv_ctx = NULL; } } static int server_init() { s_srv_ctx = (server_context_st *)malloc(sizeof(server_context_st)); if (s_srv_ctx == NULL) { return -1; } memset(s_srv_ctx, 0, sizeof(server_context_st)); int i = 0; for (;i < SIZE; i++) { s_srv_ctx->clifds[i] = -1; } return 0; } int main(int argc,char *argv[]) { int srvfd; /*初始化服务端context*/ if (server_init() < 0) { return -1; } /*创建服务,开始监听客户端请求*/ srvfd = create_server_proc(IPADDR, PORT); if (srvfd < 0) { fprintf(stderr, "socket create or bind fail.\n"); goto err; } /*开始接收并处理客户端请求*/ handle_client_proc(srvfd); server_uninit(); return 0; err: server_uninit(); return -1; } 2、client.cpp #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/select.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #define MAXLINE 1024 #define IPADDRESS "127.0.0.1" #define SERV_PORT 8787 #define max(a,b) (a > b) ? a : b static void handle_recv_msg(int sockfd, char *buf) { printf("client recv msg is:%s\n", buf); sleep(5); write(sockfd, buf, strlen(buf) +1); } static void handle_connection(int sockfd) { char sendline[MAXLINE],recvline[MAXLINE]; int maxfdp,stdineof; fd_set readfds; int n; struct timeval tv; int retval = 0; while (1) { FD_ZERO(&readfds); FD_SET(sockfd,&readfds); maxfdp = sockfd; tv.tv_sec = 5; tv.tv_usec = 0; retval = select(maxfdp+1,&readfds,NULL,NULL,&tv); if (retval == -1) { return ; } if (retval == 0) { printf("client timeout.\n"); continue; } if (FD_ISSET(sockfd, &readfds)) { n = read(sockfd,recvline,MAXLINE); if (n <= 0) { fprintf(stderr,"client: server is closed.\n"); close(sockfd); FD_CLR(sockfd,&readfds); return; } handle_recv_msg(sockfd, recvline); } } } int main(int argc,char *argv[]) { int sockfd; struct sockaddr_in servaddr; sockfd = socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); inet_pton(AF_INET,IPADDRESS,&servaddr.sin_addr); int retval = 0; retval = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); if (retval < 0) { fprintf(stderr, "connect fail,error:%s\n", strerror(errno)); return -1; } sockaddr_in clientAddr; sockaddr_in serverAddr; socklen_t addrLen = sizeof(sockaddr_in); // 获取本地ip和port getsockname(sockfd, (struct sockaddr*)&clientAddr, &addrLen); // 获取对端ip和port getpeername(sockfd, (struct sockaddr*)&serverAddr, &addrLen); printf("client[%s:%d] connect server[%s:%d]\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port), inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port)); printf("client send to server.\n"); char data[64] ={0}; sprintf(data,"hello server[%s:%d],this is client[%s:%d]", inet_ntoa(serverAddr.sin_addr), ntohs(serverAddr.sin_port), inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port)); write(sockfd, data, 64); handle_connection(sockfd); return 0; } 3、运行服务端 [root@localhost Select]# g++ -o server server.cpp [root@localhost Select]# ./server accpet clint proc is called. accept a new client: 127.0.0.1:42108 recv buf is :hello server[127.0.0.1:8787],this is client[127.0.0.1:42108] accpet clint proc is called. accept a new client: 127.0.0.1:42109 recv buf is :hello server[127.0.0.1:8787],this is client[127.0.0.1:42109] recv buf is :hello server[127.0.0.1:8787],this is client[127.0.0.1:42108] recv buf is :hello server[127.0.0.1:8787],this is client[127.0.0.1:42109] recv buf is :hello server[127.0.0.1:8787],this is client[127.0.0.1:42108] 4、运行客户端 [root@localhost Select]# g++ -o client client.cpp client[127.0.0.1:42108] connect server[127.0.0.1:8787] client send to server. client recv msg is:hello server[127.0.0.1:8787],this is client[127.0.0.1:42108] client recv msg is:hello server[127.0.0.1:8787],this is client[127.0.0.1:42108] 5、注意:if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) 这段代码的意义。 没有这段代码,先关闭服务端,这时候连接处于 TIME_WAIT状态,在开启server报错: [root@localhost poll]# ./server bind error: : Address already in use 加上上面的这段代码,就不会有这个问题。
IO多路复用__总结 |
1、IO多路复用解决什么问题? 一个连接创建一个线程,用于这个连接的交互,但是线程的开销比较大,当连接很多的时候,就会出现严重的性能问题。 2、怎么解决这个问题? 可以使用一个线程管理多个连接,一个连接对应一个socket句柄,在linux系统中就是文件描述符,这就是多路复用。 3、select特点 a、监视的FD(文件描述符)个数有限,1024个 b、对于FD集合,需要从用户态拷贝到内核态,同时进行线性扫描,存在性能问题 4、poll特点 a、poll可以认为是加强版的select,可以监视的FD个数不限,因为他是基于链表的 b、整体拷贝和线性扫描的问题,还是同样存在 5、epoll特点 a、epoll解决了上述问题,可以监视的FD个数不限 b、从用户态到内核态只拷贝一次 c、select、poll不断主动轮询,把就绪的FD设置一下,在应用程序检查是否就绪。 epoll也就是主动轮询,但是只把就绪的FD放入就绪链表中,把这个链表回调给应用程序。
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.