基于的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
原创粉丝点击