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
- epoll的设计与实现
- Linux下C++ EPOLL TCP服务器的设计与实现
- epoll简介 与 UDP server的实现
- epoll简介 与 UDP server的实现
- epoll简介 与 UDP server的实现
- linux kernel中epoll的设计和实现
- linux kernel中epoll的设计和实现
- Epoll的实现
- epoll的实现原理
- epoll的实现原理
- epoll的内核实现
- epoll 的实现原理
- epoll的内核实现
- epoll的实现原理
- EPOLL的内核实现
- epoll的实现原理
- epoll与线程池实现
- Linux的poll与epoll实现(1)---poll
- eclipse 安装安卓ADT成功,也提示重启了,但是就是没有应该有的小机器人标志
- Weka软件包管理器更新错误的解决方法
- tab键在packettracer的作用
- SP2010开发和VS2010专家"食谱"--第六章节--Web Services和REST(1)--通过REST获得数据
- 装饰模式
- epoll的设计与实现
- struts中OGNL的投影(过滤)
- linux中的poll机制分析
- 从注册流程 分析如何安全退出多个Activity 多种方式(附DEMO)
- 企业网站需要如何操作
- android application创建不了,无法选择 compile with
- SP2010开发和VS2010专家"食谱"--第六章节--Web Services和REST(2)--筛选列表数据
- C#设计模式之观察者
- Linux内存高,触发oom-killer问题解决