epoll实践
来源:互联网 发布:saas源码 java 编辑:程序博客网 时间:2024/06/04 18:03
代码做的是回射服务
客户端:
#include <errno.h>#include <netdb.h>#include <unistd.h>#include <cstdio>#include <cstdlib>#include <cstring>const int BUFFSIZ = 4096;int connect(const char * host, const char * serv){ int connfd; int n; struct addrinfo hints; struct addrinfo * res; struct addrinfo * ressave; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (0 != (n = getaddrinfo(host, serv, &hints, &res))) { printf("getaddrinfo error for %s, %s: %s\n", (NULL == host) ? "(no hostname)" : host, (NULL == serv) ? "(no servname)" : serv, gai_strerror(n)); exit(1); } ressave = res; while (NULL != res) { connfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (-1 != connfd) { if (0 == ::connect(connfd, res->ai_addr, res->ai_addrlen)) { break; } else { close(connfd); } } res = res->ai_next; } freeaddrinfo(ressave); if (NULL == res) { printf("connect failed\n"); exit(1); } return(connfd);}int main(int argc, char ** argv){ if (3 != argc) { printf("usage: %s <host> <serv>\n", argv[0]); exit(1); } int connfd = connect(argv[1], argv[2]); char buff[BUFFSIZ] = { 0 }; while (NULL != fgets(buff, BUFFSIZ, stdin)) { int len = strlen(buff); int offset = 0; while (offset < len) { int nw = write(connfd, buff + offset, len - offset); if (-1 == nw && EINTR == errno) { continue; } else if (nw <= 0) { perror("write"); exit(1); } else { offset += nw; } } offset = 0; while (len > 0) { int nr = read(connfd, buff + offset, len); if (-1 == nr) { if (EINTR != errno) { perror("read"); exit(1); } continue; } else if (0 == nr) { printf("connection close by peer\n"); exit(1); } else { len -= nr; offset += nr; } } if (-1 == fputs(buff, stdout)) { perror("fputs"); break; } } if (ferror(stdin)) { perror("fgets"); } close(connfd); exit(0); }客户端用的是阻塞式IO,所以服务器关闭时不能在第一时间得知,解决方法有:1. 改成非阻塞式IO,见UNP第十六章;2. 加上心搏函数,见UNP第二十四章。
服务器:
LT模式的epoll实现:
#include <errno.h>#include <netdb.h>#include <fcntl.h>#include <unistd.h>#include <sys/epoll.h>#include <cstdio>#include <cstdlib>#include <cstring>const int LISTENQ = 1024;const int EVENTSZ = 64;const int BUFFSIZ = 4096;int listen(const char * host, const char * serv){ int listenfd; int n; const int on = 1; struct addrinfo hints; struct addrinfo * res; struct addrinfo * ressave; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (0 != (n = getaddrinfo(host, serv, &hints, &res))) { printf("getaddrinfo error for %s, %s: %s\n", (NULL == host) ? "(no hostname)" : host, (NULL == serv) ? "(no servname)" : serv, gai_strerror(n)); exit(1); } ressave = res; while (NULL != res) { listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (-1 != listenfd) { setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (0 == bind(listenfd, res->ai_addr, res->ai_addrlen)) { break; } else { close(listenfd); } } res = res->ai_next; } freeaddrinfo(ressave); if (NULL == res) { printf("listen failed\n"); exit(1); } if (-1 == ::listen(listenfd, LISTENQ)) { printf("listen error: %s\n", strerror(errno)); exit(1); } return(listenfd);}bool setnonblock(int sockfd){ int flag = fcntl(sockfd, F_GETFL, 0); if (-1 == flag) { perror("fcntl(F_GETFL)"); return(false); } if (-1 == fcntl(sockfd, F_SETFL, flag | O_NONBLOCK)) { perror("fcntl(F_SETFL)"); return(false); } return(true);}int main(int argc, char ** argv){ if (3 != argc) { printf("usage: %s <host> <serv>\n", argv[0]); exit(1); } struct epoll_event ev; struct epoll_event events[EVENTSZ]; char buff[BUFFSIZ] = { 0 }; int epollfd = epoll_create(LISTENQ); if (-1 == epollfd) { perror("epoll_create"); exit(1); } int listenfd = listen(argv[1], argv[2]); ev.data.fd = listenfd; ev.events = EPOLLIN; if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_ADD)"); exit(1); } for ( ; ; ) { int n = epoll_wait(epollfd, events, EVENTSZ, -1); if (-1 == n) { perror("epoll_wait"); break; } for (int i = 0; i < n; ++i) { const int sockfd = events[i].data.fd; if (sockfd == listenfd) { int accefd = accept(listenfd, NULL, NULL); if (-1 == accefd) { perror("accept"); exit(1); } ev.data.fd = accefd; ev.events = EPOLLIN; if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, accefd, &ev)) { perror("epoll_ctl(EPOLL_CTL_ADD)"); close(accefd); } printf("connect by new client\n"); } else { int nr = read(sockfd, buff, BUFFSIZ); if (nr <= 0) { if (-1 == nr) { perror("read"); } else { printf("connection close by peer\n"); } if (-1 == epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_DEL)"); } close(sockfd); continue; } int nw = 0; while (nw < nr) { int n = write(sockfd, buff + nw, nr - nw); if (-1 == n && EWOULDBLOCK == errno) { continue; } else if (n <= 0) { break; } else { nw += n; } } if (nw < nr) { if (-1 == epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_DEL)"); } close(sockfd); } } } } close(epollfd); close(listenfd); exit(0);}
ET模式的epoll实现:
#include <errno.h>#include <netdb.h>#include <fcntl.h>#include <unistd.h>#include <sys/epoll.h>#include <cstdio>#include <cstdlib>#include <cstring>const int LISTENQ = 1024;const int EVENTSZ = 64;const int BUFFSIZ = 4096;int listen(const char * host, const char * serv){ int listenfd; int n; const int on = 1; struct addrinfo hints; struct addrinfo * res; struct addrinfo * ressave; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (0 != (n = getaddrinfo(host, serv, &hints, &res))) { printf("getaddrinfo error for %s, %s: %s\n", (NULL == host) ? "(no hostname)" : host, (NULL == serv) ? "(no servname)" : serv, gai_strerror(n)); exit(1); } ressave = res; while (NULL != res) { listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (-1 != listenfd) { setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (0 == bind(listenfd, res->ai_addr, res->ai_addrlen)) { break; } else { close(listenfd); } } res = res->ai_next; } freeaddrinfo(ressave); if (NULL == res) { printf("listen failed\n"); exit(1); } if (-1 == ::listen(listenfd, LISTENQ)) { printf("listen error: %s\n", strerror(errno)); exit(1); } return(listenfd);}bool setnonblock(int sockfd){ int flag = fcntl(sockfd, F_GETFL, 0); if (-1 == flag) { perror("fcntl(F_GETFL)"); return(false); } if (-1 == fcntl(sockfd, F_SETFL, flag | O_NONBLOCK)) { perror("fcntl(F_SETFL)"); return(false); } return(true);}int main(int argc, char ** argv){ if (3 != argc) { printf("usage: %s <host> <serv>\n", argv[0]); exit(1); } struct epoll_event ev; struct epoll_event events[EVENTSZ]; char buff[BUFFSIZ] = { 0 }; int epollfd = epoll_create(LISTENQ); if (-1 == epollfd) { perror("epoll_create"); exit(1); } int listenfd = listen(argv[1], argv[2]); if (!setnonblock(listenfd)) { exit(1); } ev.data.fd = listenfd; ev.events = EPOLLIN | EPOLLET; if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_ADD)"); exit(1); } for ( ; ; ) { int n = epoll_wait(epollfd, events, EVENTSZ, -1); if (-1 == n) { perror("epoll_wait"); break; } for (int i = 0; i < n; ++i) { const int sockfd = events[i].data.fd; if (sockfd == listenfd) { for ( ; ; ) { int accefd = accept(listenfd, NULL, NULL); if (-1 == accefd) { if (EAGAIN == errno) { break; } continue; } if (!setnonblock(accefd)) { close(accefd); continue; } ev.data.fd = accefd; ev.events = EPOLLIN | EPOLLET; if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, accefd, &ev)) { perror("epoll_ctl(EPOLL_CTL_ADD)"); close(accefd); } printf("connect by new client\n"); } } else { for ( ; ; ) { int nr = read(sockfd, buff, BUFFSIZ); if (-1 == nr && EAGAIN == errno) { break; } if (0 == nr) { printf("connection close by peer\n"); } if (nr <= 0) { if (-1 == epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_DEL)"); } close(sockfd); break; } int nw = 0; while (nw < nr) { int n = write(sockfd, buff + nw, nr - nw); if (-1 == n && EWOULDBLOCK == errno) { continue; } else if (n <= 0) { break; } else { nw += n; } } if (nw < nr) { if (-1 == epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, &ev)) { perror("epoll_ctl(EPOLL_CTL_DEL)"); } close(sockfd); break; } } } } } close(epollfd); close(listenfd); exit(0);}ET模式的epoll实现,在write时处理得不好,因为sockfd是非阻塞的,所以当发送缓存不足时,write会一直返回-1(errno为EWOULDBLOCK),直到有足够的发送缓存。我估计要把EPOLLOUT加到sockfd的对应event中,但这样就得为每个sockfd分配一块独立的缓存,更重要的是,我们可能得反复调用epoll_ctl(EPOLL_CTL_MOD)去增 / 减EPOLLIN / EPOLLOUT,这会降低多少效率是最值得关心的。
当然对于回射服务器没必要这样做。
- epoll实践
- I/O非阻塞函数实践:epoll
- 痛苦的epoll+线程池实践 1 程序架构
- Socket编程实践(11) --epoll原理与封装
- Socket编程实践(10) --epoll原理与封装
- Socket编程实践(11) --epoll原理与封装
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- epoll
- 矩阵-斐波那契数列
- 收藏功能
- JTabbedPane实现关闭按钮
- HBase程式設計 實做I/O操作
- Android NDK编程入门笔记
- epoll实践
- bom以及字符编码
- [Android]将应用崩溃信息汇报给开发者并重新启动应用
- 云计算国家规划将发布 云CRM成必然发展趋势
- destination host unreachable
- IDoc step by step
- 操作系统--页面置换算法(先进先出算法,最近最久未使用算法,最佳置换算法)--JAVA实现
- SIGCHLD和waitpid的使用
- JNI函数调用