Blog.csdn.net/baudgg1992/…

Epoll model mainly has two working modes: horizontal triggering (LT) and edge triggering (ET). This paper mainly focuses on edge triggering. The epoll multithreading model implemented in this paper is that the main thread waits for events to be triggered, and then puts related events into a queue, and the thread pool takes out data from the queue to process events.

Here is the implementation:

 

 
Copy the code
  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. The 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. // Handle POST message types or large files
  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. // We need to check the return value, there is no overflow here, so simple processing, actually need processing
  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 > size < / 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. // Sets the type of event to handle
  389. ev.events = EPOLLIN | EPOLLET;
  390. // Register epoll events
  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. }