└── main.cc /main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("error no: %d error msg %s\n", errno, strerror(errno)); exit(1);} 13 | 14 | void setNonBlock(int fd) { 15 | int flags = fcntl(fd, F_GETFL, 0); 16 | exit_if(flags<0, "fcntl failed"); 17 | int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); 18 | exit_if(r<0, "fcntl failed"); 19 | } 20 | 21 | void updateEvents(int efd, int fd, int events, int op) { 22 | struct epoll_event ev; 23 | memset(&ev, 0, sizeof(ev)); 24 | ev.events = events; 25 | ev.data.fd = fd; 26 | printf("%s fd %d events read %d write %d\n", 27 | op==EPOLL_CTL_MOD?"mod":"add", fd, ev.events & EPOLLIN, ev.events & EPOLLOUT); 28 | int r = epoll_ctl(efd, op, fd, &ev); 29 | exit_if(r, "epoll_ctl failed"); 30 | } 31 | 32 | void handleAccept(int efd, int fd) { 33 | struct sockaddr_in raddr; 34 | socklen_t rsz = sizeof(raddr); 35 | int cfd = accept(fd,(struct sockaddr *)&raddr,&rsz); 36 | exit_if(cfd<0, "accept failed"); 37 | sockaddr_in peer, local; 38 | socklen_t alen = sizeof(peer); 39 | int r = getpeername(cfd, (sockaddr*)&peer, &alen); 40 | exit_if(r<0, "getpeername failed"); 41 | printf("accept a connection from %s\n", inet_ntoa(raddr.sin_addr)); 42 | setNonBlock(cfd); 43 | updateEvents(efd, cfd, EPOLLIN|EPOLLOUT, EPOLL_CTL_ADD); 44 | } 45 | 46 | void handleRead(int efd, int fd) { 47 | char buf[4096]; 48 | int n = 0; 49 | while ((n=::read(fd, buf, sizeof buf)) > 0) { 50 | printf("read %d bytes\n", n); 51 | int r = ::write(fd, buf, n); //写出读取的数据 52 | //实际应用中,写出数据可能会返回EAGAIN,此时应当监听可写事件,当可写时再把数据写出 53 | exit_if(r<=0, "write error"); 54 | } 55 | if (n<0 && (errno == EAGAIN || errno == EWOULDBLOCK)) 56 | return; 57 | exit_if(n<0, "read error"); //实际应用中,n<0应当检查各类错误,如EINTR 58 | printf("fd %d closed\n", fd); 59 | close(fd); 60 | } 61 | 62 | void handleWrite(int efd, int fd) { 63 | //实际应用应当实现可写时写出数据,无数据可写才关闭可写事件 64 | updateEvents(efd, fd, EPOLLIN, EPOLL_CTL_MOD); 65 | } 66 | 67 | void loop_once(int efd, int lfd, int waitms) { 68 | const int kMaxEvents = 20; 69 | struct epoll_event activeEvs[100]; 70 | int n = epoll_wait(efd, activeEvs, kMaxEvents, waitms); 71 | printf("epoll_wait return %d\n", n); 72 | for (int i = 0; i < n; i ++) { 73 | int fd = activeEvs[i].data.fd; 74 | int events = activeEvs[i].events; 75 | if (events & (EPOLLIN | EPOLLERR)) { 76 | if (fd == lfd) { 77 | handleAccept(efd, fd); 78 | } else { 79 | handleRead(efd, fd); 80 | } 81 | } else if (events & EPOLLOUT) { 82 | handleWrite(efd, fd); 83 | } else { 84 | exit_if(1, "unknown event"); 85 | } 86 | } 87 | } 88 | 89 | int main() { 90 | short port = 99; 91 | int epollfd = epoll_create(1); 92 | exit_if(epollfd < 0, "epoll_create failed"); 93 | int listenfd = socket(AF_INET, SOCK_STREAM, 0); 94 | exit_if(listenfd < 0, "socket failed"); 95 | struct sockaddr_in addr; 96 | memset(&addr, 0, sizeof addr); 97 | addr.sin_family = AF_INET; 98 | addr.sin_port = htons(port); 99 | addr.sin_addr.s_addr = INADDR_ANY; 100 | int r = ::bind(listenfd,(struct sockaddr *)&addr, sizeof(struct sockaddr)); 101 | exit_if(r, "bind to 0.0.0.0:%d failed %d %s", port, errno, strerror(errno)); 102 | r = listen(listenfd, 20); 103 | exit_if(r, "listen failed %d %s", errno, strerror(errno)); 104 | printf("fd %d listening at %d\n", listenfd, port); 105 | setNonBlock(listenfd); 106 | updateEvents(epollfd, listenfd, EPOLLIN, EPOLL_CTL_ADD); 107 | for (;;) { //实际应用应当注册信号处理函数,退出时清理资源 108 | loop_once(epollfd, listenfd, 10000); 109 | } 110 | return 0; 111 | } --------------------------------------------------------------------------------