epoll的设计与实现

来源:互联网 发布:win10 linux 双系统 编辑:程序博客网 时间:2024/05/29 13:24
#include "epollserver.h"#include <assert.h>#include <errno.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <fcntl.h>#define MAX_EPOLL_EVENT_COUNT 30000#define EPOLL_WAIT_TIMEOUT    1000namespace lyf{EpollServer::EpollServer(void){epfd = -1;listenfd = -1;port = 6880;epollEventList = new epoll_event[MAX_EPOLL_EVENT_COUNT];assert(epollEventList != NULL);thread = 0;stop = true;}EpollServer::~EpollServer(void){if (epollEventList){delete epollEventList;epollEventList = NULL;}}int EpollServer::SetNonblocking(int fd){int opts;opts = fcntl(fd, F_GETFL);if(opts < 0){printf("fcntl(fd, GETFL)");return -1;}opts = opts|O_NONBLOCK;if(fcntl(fd, F_SETFL, opts) < 0){printf("fcntl(fd, SETFL, opts)");return -1;}return 0;}void* EpollServer::WorkProcProxy(void * param){EpollServer * p = (EpollServer*) param;p->WorkProc();}int EpollServer::WorkProc(void){listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1){printf("create socket failed\n");return -1;}int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));SetNonblocking(listenfd);sockaddr_in si;si.sin_family = AF_INET;si.sin_port = htons(port);si.sin_addr.s_addr = htonl(INADDR_ANY);if (0 != bind(listenfd, (sockaddr*)&si, sizeof(si))){printf("bind socket failed, %s\n", strerror(errno));close(listenfd);return -1;}if (0 != listen(listenfd, 1024)){printf("listen socket failed, %s\n", strerror(errno));close(listenfd);return -1;}epfd = epoll_create(MAX_EPOLL_EVENT_COUNT);if (epfd == -1){printf("epoll create failed, %s\n", strerror(errno));close(listenfd);return -1;}epoll_event e;e.events = EPOLLIN | EPOLLOUT | EPOLLET;e.data.fd = listenfd;if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &e) < 0){printf("epoll ctrl failed, %s\n", strerror(errno));close(listenfd);}while (!stop){int count = epoll_wait(epfd, epollEventList, MAX_EPOLL_EVENT_COUNT, EPOLL_WAIT_TIMEOUT);if (count < 0){printf("epoll wait failed, %s\n", strerror(errno));exit(-1);}for (int i=0; i<count; i++){epoll_event * p = &epollEventList[i];if (p->events & (EPOLLERR | EPOLLHUP)){printf("epoll events error, %s\n", strerror(errno));Connection * c = (Connection*)p->data.ptr;if (c){OnClose(c);}continue;}HandleEvent(*p);}}if (listenfd != -1){close(listenfd);listenfd = -1;}if (epfd != -1){close(epfd);epfd = -1;}std::list<Connection*>::iterator it = connectionList.begin();for (; it!=connectionList.end(); it++){Connection * c = *it;if (c && c->fd!=-1){close(c->fd);}delete c;}return 0;}int EpollServer::HandleEvent(epoll_event & e){if (e.data.fd == listenfd){sockaddr_in si;socklen_t sl = sizeof(si);int fd = accept(listenfd, (struct sockaddr*)&si, &sl);if (fd == -1){printf("accept socket failed, %s\n", strerror(errno));return -1;}//设置fd为非阻塞SetNonblocking(fd);Connection * c = new Connection;c->fd = fd;c->closed = 0;c->remoteAddress = si;epoll_event _e;_e.data.fd = fd;_e.data.ptr = c;_e.events = EPOLLIN|EPOLLOUT|EPOLLET;if (0 != epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &_e)){printf("epoll ctl add failed, %s\n", strerror(errno));close(fd);c->fd = -1;c->closed = 1;delete c;return -1;}else{OnAccept(c);}}else{Connection * c = (Connection*)e.data.ptr;if (e.events & EPOLLIN && !c->closed){OnRead(c);}if (e.events & EPOLLOUT && !c->closed){OnWrite(c);}}}int EpollServer::OnAccept(Connection * c){connectionList.push_back(c);printf("a client connect to server: %d.\n", c->fd);return 0;}int EpollServer::OnClose(Connection * c){printf("a client disconnect to server: %d.\n", c->fd);epoll_event e;e.data.fd = c->fd;e.events = EPOLLIN|EPOLLOUT|EPOLLET;if (0 != epoll_ctl(epfd, EPOLL_CTL_DEL, c->fd, &e)){printf("epoll event del failed, %s\n", strerror(errno));}close(c->fd);c->fd = -1;c->closed = 1;c->recvBuffer.clear();c->sendBuffer.clear();connectionList.remove(c);//delete c;return 0;}int EpollServer::OnError(Connection * c){return 0;}int EpollServer::OnRead(Connection * c){char buf[4096] = {0};int toread = 0;while (1){memset(buf, 0, sizeof(buf));int bytes = recv(c->fd, buf, 4095, 0);if (bytes < 0){if (errno == EINTR){continue;}else if (errno == EAGAIN){break;}else{return -1;}}else if (bytes == 0){OnClose(c);break;}else{c->recvBuffer.append(buf, bytes);}}// end whileif (!c->recvBuffer.empty()){OnResponse(c);c->recvBuffer.clear();}return 0;}int EpollServer::OnWrite(Connection * c){if (c->sendBuffer.empty()){c->writeReady = 1;printf("write ready, %d\n", c->fd);}else{int pos = 0;int towrite = c->sendBuffer.length();const char* buf = c->sendBuffer.c_str();do{int bytes = send(c->fd, buf+pos, towrite, 0);if (bytes < 0){if (errno == EINTR){continue;}else if (errno == EAGAIN){break;}else{return -1;}}else if (bytes == 0){OnClose(c);}else{pos += bytes;towrite -= bytes;}}while (towrite > 0);if (pos > 0){printf("send bytes: %d\n", pos);pthread_mutex_lock(&c->mutex);c->sendBuffer.erase(0, pos);pthread_mutex_unlock(&c->mutex);}}return 0;}int EpollServer::PostSend(Connection *c){if (c->writeReady){int pos = 0;int towrite = c->sendBuffer.length();const char* buf = c->sendBuffer.c_str();do{int bytes = send(c->fd, buf+pos, towrite, 0);if (bytes < 0){if (errno == EINTR){continue;}else if (errno == EAGAIN){break;}else{return -1;}}else if (bytes == 0){OnClose(c);}else{pos += bytes;towrite -= bytes;}}while (towrite > 0);if (pos > 0){printf("send bytes: %d\n", pos);pthread_mutex_lock(&c->mutex);c->sendBuffer.erase(0, pos);pthread_mutex_unlock(&c->mutex);}}else{c->writeReady = 0;printf("post send not ready\n");}return 0;}bool EpollServer::Start(void){stop = false;if (0 != pthread_create(&thread, 0, WorkProcProxy, this)){printf("create thread failed, %s\n", strerror(errno));return false;}return true;}void EpollServer::Stop(void){stop = true;pthread_join(thread, 0);}}

0 0
原创粉丝点击