基于的epoll模型的简单http服务器

https://blog.csdn.net/baudgg1992/article/details/51155095

 epoll模型主要有2种工作方式:水平触发(LT)和边缘触发(ET),本文主要是关于边缘触发的。本文实现的epoll多线程模型主要是,主线程等待事件触发,然后把相关事件放入队列,线程池从队列中取出数据处理事件。

下面是具体实现:

 
  1. #include <stdarg.h>

  2. #include <errno.h>

  3. #include <stdio.h>

  4. #include <fcntl.h>

  5. #include <unistd.h>

  6. #include <time.h>

  7. #include <sys/types.h>

  8. #include <sys/stat.h>

  9. #include <sys/epoll.h>

  10. #include <sys/sendfile.h>

  11. #include <dirent.h>

  12. #include <netinet/in.h>

  13. #include <sys/socket.h>

  14. #include <resolv.h>

  15. #include <arpa/inet.h>

  16. #include <stdlib.h>

  17. #include <signal.h>

  18. #include <getopt.h>

  19. #include <string.h>

  20. #include <string>

  21. #include <iostream>

  22. #include "ThreadPool.h"

  23. using namespace std;

  24.  
  25. static string strIP="192.168.0.168";

  26. static int nPort=8088;

  27. static string strDir="/home/temp/http_server";

  28. const int MAX_EVENT=10;

  29. struct epoll_event ev, events[MAX_EVENT];

  30. int epfd;

  31. enum {NeedRead_Event,Reading_Event,Error_Req,NeedWrite_Event,Writing_Event};

  32.  
  33. struct Task

  34. {

  35. epoll_event m_oEvent;

  36. string m_strFilePath;

  37. int m_nCurSize;

  38. int m_nType;

  39. int m_nReadOrWritefd;

  40. int m_nFileLen;

  41. int m_nSockfd;

  42. };

  43.  
  44. char* dir_up(char *Path)

  45. {

  46. int len;

  47. len = strlen(Path);

  48. if (len > 1 && Path[len - 1] == '/')

  49. {

  50. len--;

  51. }

  52. while (Path[len - 1] != '/' && len > 1)

  53. {

  54. len--;

  55. }

  56. Path[len] = 0;

  57. return Path;

  58. }

  59.  
  60. char *strsplit(char **s,char del)

  61. {

  62. char *d, *tok;

  63. if (!s || !*s)

  64. return NULL;

  65. tok = *s;

  66. d = strchr(tok, del);

  67. if (d) {

  68. *d = '\0';

  69. *s = d + 1;

  70. } else

  71. *s = NULL;

  72. return tok;

  73. }

  74.  
  75. char* urldecode( char* encd, char* decd)

  76. {

  77. int j,i;

  78. char *cd = encd;

  79. char p[2];

  80. unsigned int num;

  81. j=0;

  82.  
  83. for( i = 0; i < strlen(cd); i++ )

  84. {

  85. memset( p, '\0', 2 );

  86. if( cd[i] != '%' )

  87. {

  88. decd[j++] = cd[i];

  89. continue;

  90. }

  91.  
  92. p[0] = cd[++i];

  93. p[1] = cd[++i];

  94.  
  95. p[0] = p[0] - 48 - ((p[0] >= 'A') ? 7 : 0) - ((p[0] >= 'a') ? 32 : 0);

  96. p[1] = p[1] - 48 - ((p[1] >= 'A') ? 7 : 0) - ((p[1] >= 'a') ? 32 : 0);

  97. decd[j++] = (p[0] * 16 + p[1]);

  98.  
  99. }

  100. decd[j] = '\0';

  101.  
  102. return decd;

  103. }

  104.  
  105.  
  106. void *ReadTask(void *arg)

  107. {

  108.  
  109. Task *pTask=(Task*)arg;

  110. char *cBuffer=new char[128*1024];

  111. if(pTask->m_nType==NeedRead_Event)

  112. {

  113. int nSize=read(pTask->m_nSockfd,cBuffer,128*1024);

  114. if(nSize==0)

  115. {

  116. close(pTask->m_nSockfd);

  117. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  118. delete pTask;

  119. return NULL;

  120. }

  121. else if(nSize<0)

  122. {

  123. cout<<errno<<endl;

  124. if (errno == EINTR)

  125. {

  126. pTask->m_oEvent.events = EPOLLIN | EPOLLET | EPOLLONESHOT;

  127. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  128. return NULL;

  129. }

  130. if (errno == EAGAIN)

  131. {

  132. return NULL;

  133. }

  134. }

  135. else

  136. {

  137. char *cMethon=strsplit(&cBuffer,' ');

  138. if(cBuffer==NULL)

  139. {

  140. pTask->m_nType=Error_Req;

  141. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  142. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  143. return NULL;

  144. }

  145. char *cUrl=strsplit(&cBuffer,' ');

  146. if(cUrl==NULL)

  147. {

  148. pTask->m_nType=Error_Req;

  149. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  150. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  151. return NULL;

  152. }

  153. char *decUrl=new char [strlen(cUrl)];

  154. urldecode(cUrl,decUrl);

  155. pTask->m_nType=NeedWrite_Event;

  156. //pTask->m_strFilePath=UrlDecode(cUrl);

  157. pTask->m_strFilePath=decUrl;

  158. delete [] decUrl;

  159. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  160. epoll_ctl(epfd, EPOLL_CTL_MOD, pTask->m_nSockfd, &(pTask->m_oEvent));

  161. return NULL;

  162. }

  163.  
  164. }

  165. else

  166. {

  167. //处理post消息类型或者大文件

  168. return NULL;

  169. }

  170. }

  171. const string strError="HTTP/1.1 404 ERROR\r\nServer:SimpleServer\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n";

  172.  
  173. void *WriteTask(void *arg)

  174. {

  175. Task *pTask=(Task*)arg;

  176. char cBuffer[128*1024];

  177. if(pTask->m_nType==NeedWrite_Event)

  178. {

  179. struct dirent *pDir;

  180. struct stat oStat;

  181. DIR *dir;

  182. string strFilePath=strDir+pTask->m_strFilePath;

  183. if(stat(strFilePath.c_str(),&oStat))

  184. {

  185. //需要对返回值进行判断,这边不会溢出所以简单处理,实际上需要处理

  186. 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));

  187. 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));

  188. int nWriteCount=write(pTask->m_nSockfd,cBuffer,nSize);

  189. /*

  190. if(nWriteCount<0)

  191. {

  192. if(errno == EAGAIN)

  193. {

  194. pTask->m_nType=Writing_Event;

  195. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  196. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  197. }

  198. }

  199. */

  200. close(pTask->m_nSockfd);

  201. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  202. delete pTask;

  203. return NULL;

  204. }

  205. if(S_ISREG(oStat.st_mode))

  206. {

  207. pTask->m_nReadOrWritefd = open(strFilePath.c_str(), O_RDONLY);

  208. pTask->m_nFileLen = lseek(pTask->m_nReadOrWritefd, 0, SEEK_END);

  209. lseek(pTask->m_nReadOrWritefd, 0, SEEK_SET);

  210. 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);

  211. write(pTask->m_nSockfd,cBuffer,nSize);

  212. pTask->m_nType=Writing_Event;

  213. pTask->m_nCurSize=0;

  214. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  215. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  216. }

  217. else if(S_ISDIR(oStat.st_mode))

  218. {

  219. int nSize=0;

  220. dir=opendir(strFilePath.c_str());

  221. 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>"

  222. "<body><font size=+4>Linux directory access server</font><br><hr width=\"100%%\"><br><center>"

  223. "<table border cols=3 width=\"100%%\">", strFilePath.c_str());

  224. nSize+=sprintf(cBuffer+nSize, "<caption><font size=+3>dir %s</font></caption>\n",strFilePath.c_str());

  225. nSize+=sprintf(cBuffer+nSize, "<tr><td>name</td><td>大小</td><td>change time</td></tr>\n");

  226. if(dir==NULL)

  227. {

  228. nSize+=sprintf(cBuffer+nSize,"</table><font color=\"CC0000\" size=+2>%s</font></body></html>",strerror(errno));

  229. write(pTask->m_nSockfd,cBuffer,nSize);

  230. return NULL;

  231. }

  232. while((pDir=readdir(dir))!=NULL)

  233. {

  234. string strFileName=string(pTask->m_strFilePath.c_str())+"/"+string(pDir->d_name);

  235. nSize+=sprintf(cBuffer+nSize,"<tr>");

  236. string strDirFilePath=strFilePath+"/"+pDir->d_name;

  237. if(stat(strDirFilePath.c_str(),&oStat)==0)

  238. {

  239. if(strcmp(pDir->d_name, "..") == 0)

  240. {

  241. char path[PATH_MAX];

  242. strcpy(path,pTask->m_strFilePath.c_str());

  243. nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">..</a></td>",strIP.c_str(), nPort,dir_up(path));

  244. }

  245. else if(strcmp(pDir->d_name,".")==0)

  246. {

  247. nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">.</a></td>",strIP.c_str(),nPort, pTask->m_strFilePath.c_str());

  248. }

  249. else

  250. {

  251. nSize+=sprintf(cBuffer+nSize,"<td><a href=\"http://%s:%d%s\">%s</a></td>", strIP.c_str(),nPort, strFileName.c_str(),pDir->d_name);

  252. }

  253. if (S_ISDIR(oStat.st_mode))

  254. {

  255. nSize+=sprintf(cBuffer+nSize, "<td>dir</td>");

  256. }

  257. else if (S_ISREG(oStat.st_mode))

  258. {

  259. nSize+=sprintf(cBuffer+nSize, "<td>%d</td>", oStat.st_size);

  260. }

  261. else if (S_ISLNK(oStat.st_mode))

  262. {

  263. nSize+=sprintf(cBuffer+nSize, "<td>interlinkage</td>");

  264. }

  265. else if (S_ISCHR(oStat.st_mode))

  266. {

  267. nSize+=sprintf(cBuffer+nSize, "<td>char device</td>");

  268. }

  269. else if (S_ISBLK(oStat.st_mode))

  270. {

  271. nSize+=sprintf(cBuffer+nSize, "<td>chunk device</td>");

  272. }

  273. else if (S_ISFIFO(oStat.st_mode))

  274. {

  275. nSize+=sprintf(cBuffer+nSize, "<td>FIFO</td>");

  276. }

  277. else if (S_ISSOCK(oStat.st_mode))

  278. {

  279. nSize+=sprintf(cBuffer+nSize, "<td>Socket</td>");

  280. }

  281. else

  282. {

  283. nSize+=sprintf(cBuffer+nSize, "<td>(unknow)</td>");

  284. nSize+=sprintf(cBuffer+nSize, "<td>%s</td>", ctime(&oStat.st_ctime));

  285. }

  286. }

  287. nSize+=sprintf(cBuffer+nSize, "</tr>\n");

  288. }

  289. closedir(dir);

  290. nSize+=sprintf(cBuffer+nSize, "</tr>\n");

  291. write(pTask->m_nSockfd,cBuffer,nSize);

  292. close(pTask->m_nSockfd);

  293. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  294. delete pTask;

  295. }

  296. else

  297. {

  298. int nSize=0;

  299. 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%%\">");

  300. 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());

  301. write(pTask->m_nSockfd,cBuffer,nSize);

  302. close(pTask->m_nSockfd);

  303. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  304. delete pTask;

  305. }

  306. }

  307. else if(pTask->m_nType==Writing_Event)

  308. {

  309. int nSize=128*1024;

  310. if(pTask->m_nFileLen-pTask->m_nCurSize<128*1024)

  311. {

  312. nSize=pTask->m_nFileLen-pTask->m_nCurSize;

  313. }

  314. nSize=sendfile(pTask->m_nSockfd,pTask->m_nReadOrWritefd,NULL,nSize);

  315. pTask->m_nCurSize+=nSize;

  316. if(pTask->m_nCurSize!=pTask->m_nFileLen)

  317. {

  318. pTask->m_oEvent.events = EPOLLOUT | EPOLLET | EPOLLONESHOT;

  319. epoll_ctl(epfd, EPOLL_CTL_MOD,pTask->m_nSockfd, &(pTask->m_oEvent));

  320. }

  321. else

  322. {

  323. close(pTask->m_nReadOrWritefd);

  324. close(pTask->m_nSockfd);

  325. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  326. delete pTask;

  327. }

  328. }

  329. else if(pTask->m_nType==Error_Req)

  330. {

  331. write(pTask->m_nSockfd,strError.c_str(),strError.size());

  332. close(pTask->m_nSockfd);

  333. epoll_ctl(epfd, EPOLL_CTL_DEL,pTask->m_nSockfd, &(pTask->m_oEvent));

  334. delete pTask;

  335. }

  336. return NULL;

  337. }

  338.  
  339.  
  340. void setnonblocking(int sock)

  341. {

  342. int opts;

  343. opts = fcntl(sock, F_GETFL);

  344. if (opts < 0)

  345. {

  346. cout<<"fcntl(sock,F_GETFL) error"<<endl;

  347. return ;

  348. }

  349. opts = opts | O_NONBLOCK;

  350. if (fcntl(sock, F_SETFL, opts) < 0)

  351. {

  352. cout<<"fcntl(sock,F_GETFL) error"<<endl;

  353. return ;

  354. }

  355. }

  356. int main()

  357. {

  358. ThreadPool mPool;

  359. //signal(SIGPIPE,SIG_IGN);

  360. //signal(SIGCHLD,SIG_IGN);

  361. epfd = epoll_create(MAX_EVENT);

  362. struct sockaddr_in addr;

  363. int sock_fd,addrlen;

  364. if((sock_fd=socket(PF_INET,SOCK_STREAM,0))<0)

  365. {

  366. cout<<"socket init failed..."<<endl;

  367. }

  368.  
  369. addrlen = 1;

  370. setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));

  371.  
  372. setnonblocking(sock_fd);

  373. addr.sin_family=AF_INET;

  374. addr.sin_port=htons(nPort);

  375. addr.sin_addr.s_addr=htonl(INADDR_ANY);

  376. addrlen=sizeof(struct sockaddr_in);

  377. if(bind(sock_fd,(struct sockaddr*)&addr,addrlen)<0)

  378. {

  379. cout<<"bind failed..."<<endl;

  380. }

  381. if(listen(sock_fd,MAX_EVENT)<0)

  382. {

  383. cout<<"listen failed..."<<endl;

  384. }

  385. cout<<"server start..."<<endl;

  386.  
  387. ev.data.fd = sock_fd;

  388. // 设置要处理的事件类型

  389. ev.events = EPOLLIN | EPOLLET;

  390. // 注册 epoll 事件

  391. epoll_ctl(epfd, EPOLL_CTL_ADD, sock_fd, &ev);

  392. struct sockaddr_in clientaddr ;

  393. for (;;)

  394. {

  395. int nfds = epoll_wait(epfd, events, MAX_EVENT, -1);

  396. for(int i=0;i<nfds;++i)

  397. {

  398. if(events[i].data.fd==sock_fd)

  399. {

  400. int connfd;

  401. socklen_t clilen = sizeof(clientaddr);

  402. connfd = accept(sock_fd, (sockaddr *)&clientaddr, &clilen);

  403. if(connfd == -1)

  404. {

  405. cout<<"accept error:"<<errno<<endl;

  406. continue;

  407. }

  408. else

  409. {

  410. cout<<"connect from:"<<inet_ntoa(clientaddr.sin_addr)<<":"<<ntohs(clientaddr.sin_port)<<endl;

  411. }

  412. setnonblocking(connfd);

  413. int nRecvBuf=128*1024;

  414. setsockopt(connfd, SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));

  415. int nSendBuf=128*1024;

  416. setsockopt(connfd, SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

  417. int nNetTimeout=3000;

  418. setsockopt(connfd, SOL_SOCKET, SO_SNDTIMEO, (const char *)&nNetTimeout, sizeof(int));

  419. setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&nNetTimeout, sizeof(int));

  420. Task *pTask=new Task;

  421. pTask->m_nType=NeedRead_Event;

  422. pTask->m_nSockfd=connfd;

  423. pTask->m_oEvent.events = EPOLLIN | EPOLLET |EPOLLONESHOT;

  424. pTask->m_oEvent.data.ptr = pTask;

  425. epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &(pTask->m_oEvent));

  426. }

  427. else if(events[i].events & EPOLLIN)

  428. {

  429.  
  430. mPool.AddWorker(ReadTask,events[i].data.ptr);

  431. }

  432. else if(events[i].events & EPOLLOUT)

  433. {

  434. mPool.AddWorker(WriteTask,events[i].data.ptr);

  435. }

  436.  
  437.  
  438. }

  439.  
  440. }

  441. }

猜你喜欢

转载自blog.csdn.net/libaineu2004/article/details/81742790
今日推荐