A simple echoserver.
Listen on the configured network address (or 0.0.0.0)
// create listen int init_listen_sock(int epsfd, unsigned short port) { std::vector<int> ip_list; if (!get_ipv4_addr(ip_list)) return 1; for (int i = 0; i < ip_list.size(); i++) { int sfd = 0; if ((sfd = listen_on(ip_list[i], port)) < 0) return 1; int ipv4 = ip_list[i]; unsigned char * pipv4 = (unsigned char *)&ipv4; LOG_INFO("listen on host: [%d.%d.%d.%d : %d]\n", pipv4[0], pipv4[1], pipv4[2], pipv4[3], port ); if (ep_add(epsfd, sfd, true)) return 1; } return 0; }
Create an epoll handle
int ep_init() { return epoll_create(5); }
Add a socket to the epoll queue
int ep_add(int epfd, int sfd, bool is_listen_sock) { struct epoll_event evt; evt.events = EPOLLIN //| EPOLLOUT | EPOLLET ; evt.data.ptr = malloc(sizeof(struct epoll_sock_t)); epoll_sock_t * ptr = (epoll_sock_t *) evt.data.ptr; ptr->sock_fd = sfd; ptr->listen = is_listen_sock; int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &evt); return ret; }
Delete a socket from the epoll queue
int ep_del(int epfd, int sfd) { int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, sfd, 0); return ret; }
Disable the epoll handle
int ep_shutdown(int epfd) { close(epfd); return 0; }
Wait on the epoll queue. If a read/write event occurs, the user function is called back.
int ep_wait(int epfd, ep_wait_cb_t epw_cb, void * userdata) { struct epoll_event evts[EP_MAX_WAIT_NR] = { 0 }; for (;;) { int nfds = 0; errno = 0; if (0 >= (nfds = epoll_wait(epfd, evts, EP_MAX_WAIT_NR, -1)) && errno != EINTR) { break;// stop } for (int i = 0; i < nfds; i++) { epw_cb(epfd, &evts[i], userdata); } } }
A simple startup thread
void * ep_thread(void * args){ int epfd = 0; if ((epfd = ep_init()) <= 0) return 0; unsigned short port = 8000; if (init_listen_sock(epfd, port)) { return 0; } void * userdata = 0; if (ep_wait(epfd, ep_event_callback, userdata)) { return 0; } if (ep_shutdown(epfd)) { return 0; }; return (void *)0;}
User callback function
intep_event_callback(int epfd, struct epoll_event * evt, void * userdata){ epoll_sock_t * ptr = (epoll_sock_t *) (evt->data.ptr); if (evt->events & EPOLLIN) { printsockinfo(ptr->sock_fd); if (ptr->listen) // for listen socket { sockaddr_in csa; socklen_t csalen = sizeof(csa); int clientsfd = 0; errno = 0; while ((clientsfd = accept(ptr->sock_fd, (struct sockaddr *) &csa, &csalen)) > 0) { if (setnonblocking(clientsfd)) { LOG_ERROR("fail to set client socket to non-blocking.\n"); close(clientsfd); continue; } if (ep_add(epfd, clientsfd, false)) { LOG_ERROR("fail to add client socket to epoll.\n"); close(clientsfd); continue; } } if (errno != EAGAIN && errno != EINTR) close(ptr->sock_fd); } else { errno = 0; char msg [0x200] = ""; while (recv(ptr->sock_fd, msg, 0x200, 0) > 0) { tm_printstamp(); LOG_INFO(" - %s \r\n", msg); fflush(stdout); } if (errno != EAGAIN && errno != EINTR) { close(ptr->sock_fd); LOG_ERROR("errno=[%d]\n", errno); } } } else if (evt->events & EPOLLERR) { LOG_INFO("catch an EPOLLERR, sockfd=[%d]. errno=[%d]\n", ptr->sock_fd, errno); close(ptr->sock_fd); } else { LOG_INFO("epoll events [%d] Ignored, sockfd = [%d].\n", evt->events, ptr->sock_fd); } return 0;}
Project source file, including makefile.
Http://hi.csdn.net/attachment/201112/30/0_1325239083n82M.gif