基于的epoll模型的简单http服务器
来源:互联网 发布:数字货币交易系统源码 编辑:程序博客网 时间:2024/05/23 01:23
epoll模型主要有2种工作方式:水平触发(LT)和边缘触发(ET),本文主要是关于边缘触发的。本文实现的epoll多线程模型主要是,主线程等待事件触发,然后把相关事件放入队列,线程池从队列中取出数据处理事件。
下面是具体实现:
#include <stdarg.h>#include <errno.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <time.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/epoll.h>#include <sys/sendfile.h>#include <dirent.h>#include <netinet/in.h>#include <sys/socket.h>#include <resolv.h>#include <arpa/inet.h>#include <stdlib.h>#include <signal.h>#include <getopt.h>#include <string.h>#include <string>#include <iostream>#include "ThreadPool.h"using namespace std;static string strIP="192.168.0.168";static int nPort=8088;static string strDir="/home/temp/http_server";const int MAX_EVENT=10;struct epoll_event ev, events[MAX_EVENT];int epfd;enum {NeedRead_Event,Reading_Event,Error_Req,NeedWrite_Event,Writing_Event};struct Task{epoll_event m_oEvent;string m_strFilePath;int m_nCurSize;int m_nType;int m_nReadOrWritefd;int m_nFileLen;int m_nSockfd;};char* dir_up(char *Path){ int len; len = strlen(Path); if (len > 1 && Path[len - 1] == '/') { len--; } while (Path[len - 1] != '/' && len > 1) { len--; } Path[len] = 0; return Path;}char *strsplit(char **s,char del){char *d, *tok;if (!s || !*s)return NULL;tok = *s;d = strchr(tok, del);if (d) {*d = '\0';*s = d + 1;} else*s = NULL;return tok;} char* urldecode( char* encd, char* decd) { int j,i; char *cd = encd; char p[2]; unsigned int num; j=0; for( i = 0; i < strlen(cd); i++ ) { memset( p, '\0', 2 ); if( cd[i] != '%' ) { decd[j++] = cd[i]; continue; } p[0] = cd[++i]; p[1] = cd[++i]; p[0] = p[0] - 48 - ((p[0] >= 'A') ? 7 : 0) - ((p[0] >= 'a') ? 32 : 0); p[1] = p[1] - 48 - ((p[1] >= 'A') ? 7 : 0) - ((p[1] >= 'a') ? 32 : 0); decd[j++] = (p[0] * 16 + p[1]); } decd[j] = '\0'; return decd; } void *ReadTask(void *arg){Task *pTask=(Task*)arg;char *cBuffer=new char[128*1024];if(pTask->m_nType==NeedRead_Event){int nSize=read(pTask->m_nSockfd,cBuffer,128*1024);if(nSize==0){close(pTask->m_nSockfd);epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));delete pTask;return NULL;}else if(nSize<0){cout<<errno<<endl;if (errno == EINTR){pTask->m_oEvent.events = EPOLLIN | EPOLLET | EPOLLONESHOT; epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));return NULL; } if (errno == EAGAIN){return NULL;}}else{char *cMethon=strsplit(&cBuffer,' ');if(cBuffer==NULL){pTask->m_nType=Error_Req;pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));return NULL;}char *cUrl=strsplit(&cBuffer,' ');if(cUrl==NULL){pTask->m_nType=Error_Req;pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));return NULL;}char *decUrl=new char [strlen(cUrl)];urldecode(cUrl,decUrl);pTask->m_nType=NeedWrite_Event;//pTask->m_strFilePath=UrlDecode(cUrl);pTask->m_strFilePath=decUrl;delete [] decUrl;pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; epoll_ctl(epfd, EPOLL_CTL_MOD, pTask->m_nSockfd, &(pTask->m_oEvent)); return NULL;}}else{//处理post消息类型或者大文件return NULL;}}const string strError="HTTP/1.1 404 ERROR\r\nServer:SimpleServer\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n";void *WriteTask(void *arg){Task *pTask=(Task*)arg;char cBuffer[128*1024]; if(pTask->m_nType==NeedWrite_Event) {struct dirent *pDir; struct stat oStat; DIR *dir; string strFilePath=strDir+pTask->m_strFilePath; if(stat(strFilePath.c_str(),&oStat)) {//需要对返回值进行判断,这边不会溢出所以简单处理,实际上需要处理 int nSize=sprintf(cBuffer,"HTTP/1.1 200 OK\r\nServer:SimpleServer\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%d - %s</title></head>" "<body><font size=+4>Linux directory access server</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">", errno, strerror(errno)); nSize+=sprintf(cBuffer+nSize,"</table><font color=\"CC0000\" size=+2>Please contact the administrator consulting why appear as follows error message:\n%s %s</font></body></html>", pTask->m_strFilePath.c_str(), strerror(errno));int nWriteCount=write(pTask->m_nSockfd,cBuffer,nSize);/*if(nWriteCount<0){if(errno == EAGAIN){pTask->m_nType=Writing_Event; pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent)); } }*/close(pTask->m_nSockfd); epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent)); delete pTask;return NULL; }if(S_ISREG(oStat.st_mode)) {pTask->m_nReadOrWritefd = open(strFilePath.c_str(), O_RDONLY); pTask->m_nFileLen = lseek(pTask->m_nReadOrWritefd, 0, SEEK_END); lseek(pTask->m_nReadOrWritefd, 0, SEEK_SET); int nSize=sprintf(cBuffer,"HTTP/1.1 200 OK\r\nServer:SimpleServer\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n",pTask->m_nFileLen);write(pTask->m_nSockfd,cBuffer,nSize);pTask->m_nType=Writing_Event;pTask->m_nCurSize=0; pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));}else if(S_ISDIR(oStat.st_mode)) {int nSize=0; dir=opendir(strFilePath.c_str()); nSize+=sprintf(cBuffer+nSize, "HTTP/1.1 200 OK\r\nServer:SimpleServer\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%s</title></head>" "<body><font size=+4>Linux directory access server</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">", strFilePath.c_str()); nSize+=sprintf(cBuffer+nSize, "<caption><font size=+3>dir %s</font></caption>\n",strFilePath.c_str()); nSize+=sprintf(cBuffer+nSize, "<tr><td>name</td><td>大小</td><td>change time</td></tr>\n"); if(dir==NULL) { nSize+=sprintf(cBuffer+nSize,"</table><font color=\"CC0000\" size=+2>%s</font></body></html>",strerror(errno)); write(pTask->m_nSockfd,cBuffer,nSize);return NULL; } while((pDir=readdir(dir))!=NULL) { string strFileName=string(pTask->m_strFilePath.c_str())+"/"+string(pDir->d_name); nSize+=sprintf(cBuffer+nSize,"<tr>"); string strDirFilePath=strFilePath+"/"+pDir->d_name; if(stat(strDirFilePath.c_str(),&oStat)==0) { if(strcmp(pDir->d_name, "..") == 0) {char path[PATH_MAX]; strcpy(path,pTask->m_strFilePath.c_str()); nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">..</a></td>",strIP.c_str(), nPort,dir_up(path)); } else if(strcmp(pDir->d_name,".")==0) { nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">.</a></td>",strIP.c_str(),nPort, pTask->m_strFilePath.c_str()); } else { nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">%s</a></td>", strIP.c_str(),nPort, strFileName.c_str(),pDir->d_name); } if (S_ISDIR(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>dir</td>"); } else if (S_ISREG(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>%d</td>", oStat.st_size); } else if (S_ISLNK(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>interlinkage</td>"); } else if (S_ISCHR(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>char device</td>"); } else if (S_ISBLK(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>chunk device</td>"); } else if (S_ISFIFO(oStat.st_mode)) { nSize+=sprintf(cBuffer+nSize, "<td>FIFO</td>"); } else if (S_ISSOCK(oStat.st_mode)){nSize+=sprintf(cBuffer+nSize, "<td>Socket</td>"); } else { nSize+=sprintf(cBuffer+nSize, "<td>(unknow)</td>"); nSize+=sprintf(cBuffer+nSize, "<td>%s</td>", ctime(&oStat.st_ctime)); } } nSize+=sprintf(cBuffer+nSize, "</tr>\n"); }closedir(dir); nSize+=sprintf(cBuffer+nSize, "</tr>\n");write(pTask->m_nSockfd,cBuffer,nSize);close(pTask->m_nSockfd); epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent)); delete pTask; } else {int nSize=0; nSize+=sprintf(cBuffer+nSize,"HTTP/1.1 200 OK\r\nServer:SimpleServer\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n<html><head><title>permission denied</title></head>" "<body><font size=+4>Linux directory access server</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">"); nSize+=sprintf(cBuffer+nSize,"</table><font color=\"CC0000\" size=+2>You visit resources '%s' be under an embargo,Please contact the administrator to solve!</font></body></html& gt;", pTask->m_strFilePath.c_str()); write(pTask->m_nSockfd,cBuffer,nSize);close(pTask->m_nSockfd); epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent)); delete pTask;}}else if(pTask->m_nType==Writing_Event){int nSize=128*1024;if(pTask->m_nFileLen-pTask->m_nCurSize<128*1024){nSize=pTask->m_nFileLen-pTask->m_nCurSize;}nSize=sendfile(pTask->m_nSockfd,pTask->m_nReadOrWritefd,NULL,nSize);pTask->m_nCurSize+=nSize;if(pTask->m_nCurSize!=pTask->m_nFileLen){pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT; epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));}else{close(pTask->m_nReadOrWritefd);close(pTask->m_nSockfd); epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent)); delete pTask;}}else if(pTask->m_nType==Error_Req){write(pTask->m_nSockfd,strError.c_str(),strError.size());close(pTask->m_nSockfd); epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent)); delete pTask;}return NULL;}void setnonblocking(int sock){ int opts; opts = fcntl(sock, F_GETFL); if (opts < 0) { cout<<"fcntl(sock,F_GETFL) error"<<endl; return ; } opts = opts | O_NONBLOCK; if (fcntl(sock, F_SETFL, opts) < 0) { cout<<"fcntl(sock,F_GETFL) error"<<endl; return ; }}int main(){ThreadPool mPool;//signal(SIGPIPE,SIG_IGN); //signal(SIGCHLD,SIG_IGN);epfd = epoll_create(MAX_EVENT);struct sockaddr_in addr;int sock_fd,addrlen; if((sock_fd=socket(PF_INET,SOCK_STREAM,0))<0) { cout<<"socket init failed..."<<endl; } addrlen = 1; setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));setnonblocking(sock_fd); addr.sin_family=AF_INET; addr.sin_port=htons(nPort); addr.sin_addr.s_addr=htonl(INADDR_ANY); addrlen=sizeof(struct sockaddr_in); if(bind(sock_fd,(struct sockaddr*)&addr,addrlen)<0) { cout<<"bind failed..."<<endl; }if(listen(sock_fd,MAX_EVENT)<0) { cout<<"listen failed..."<<endl;} cout<<"server start..."<<endl;ev.data.fd = sock_fd; // 设置要处理的事件类型 ev.events = EPOLLIN | EPOLLET; // 注册 epoll 事件 epoll_ctl(epfd, EPOLL_CTL_ADD, sock_fd, &ev);struct sockaddr_in clientaddr ; for (;;){int nfds = epoll_wait(epfd, events, MAX_EVENT, -1);for(int i=0;i<nfds;++i){if(events[i].data.fd==sock_fd){int connfd; socklen_t clilen = sizeof(clientaddr); connfd = accept(sock_fd, (sockaddr *)&clientaddr, &clilen); if(connfd == -1){ cout<<"accept error:"<<errno<<endl; continue; }else{ cout<<"connect from:"<<inet_ntoa(clientaddr.sin_addr)<<":"<<ntohs(clientaddr.sin_port)<<endl;}setnonblocking(connfd);int nRecvBuf=128*1024;setsockopt(connfd, SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));int nSendBuf=128*1024;setsockopt(connfd, SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));int nNetTimeout=3000;setsockopt(connfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&nNetTimeout, sizeof(int));setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&nNetTimeout, sizeof(int)); Task *pTask=new Task;pTask->m_nType=NeedRead_Event;pTask->m_nSockfd=connfd; pTask->m_oEvent.events = EPOLLIN | EPOLLET |EPOLLONESHOT; pTask->m_oEvent.data.ptr = pTask; epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &(pTask->m_oEvent));}else if(events[i].events & EPOLLIN){mPool.AddWorker(ReadTask,events[i].data.ptr);}else if(events[i].events & EPOLLOUT){mPool.AddWorker(WriteTask,events[i].data.ptr);}}}}
0 0
- 基于的epoll模型的简单http服务器
- 基于epoll的简单的http服务器
- 基于epoll的简单的http服务器
- Linux下利用线程池模型+epoll实现简单的HTTP服务器
- 基于epoll实现的一个简单web服务器
- epoll版本的http服务器
- 基于Linux epoll模型的Simple
- C++ 基于epoll,poll的IO复用的Reactor模型服务器框架 -- FAS
- 基于resion实现epoll的Socket服务器
- 基于epoll服务器的测试计划
- 最简单的Epoll模型代码
- 简易HTTP服务器(epoll模型ET版本)
- IOCP模型与EPOLL模型的比较 服务器优化
- 多路转接-EPOLL 及简单的EPOLL服务器实现
- 关于epoll服务器反馈的简单实现
- 简单的http服务器
- 基于GO语言最简单的HTTP服务器
- 基于tcp自己实现简单的HTTP服务器
- LeetCode Word Pattern
- SQL2005四个排名函数(row_number、rank、dense_rank和ntile)的比较
- Python叠加两幅栅格图像
- java多线程的好处.1
- 41.leetcode题目217. Contains Duplicate(哈希方法还没做)
- 基于的epoll模型的简单http服务器
- 06 VoLTE - Signaling - Call Release and Error Handling
- BSoj : 4608【CQOI2016】路由表
- 关于java以及引申到其他技术的学习方法的小结
- Ubuntu 14.04 LTS 版升级到 GCC 4.9.2
- Java中判断List为空
- MVP浅尝----从一个自定义View说起
- 一道事件委托面试题 - 猫叫老鼠跑主人醒
- OD三种断点原理