epoll + 线程池 回应服务器(Linux) ---可以支持上万个连接

来源:互联网 发布:网络线材厂家 编辑:程序博客网 时间:2024/05/17 03:03
http://blog.csdn.net/guanyijun123/article/details/8475880[cpp] view plaincopy
  1. //ptypes  
  2. #include "ptime.h"  
  3. #include "pinet.h"  
  4. #include "ptypes.h"  
  5. #include "pasync.h"  
  6. #include "logfile.h"  
  7.   
  8. //network  
  9. #include <sys/socket.h>  
  10. #include <sys/epoll.h>  
  11. #include <netinet/in.h>  
  12. #include <arpa/inet.h>  
  13. #include <fcntl.h>  
  14. #include <unistd.h>  
  15. #include <stdio.h>  
  16. #include <errno.h>  
  17. #include <iostream>  
  18. #include <set>  
  19. using namespace std;  
  20. USING_PTYPES  
  21. #define MAX_EVENTS 10000  
  22. #define maxtoken 1024  
  23. const int maxthreads = 64;  
  24. const int MSG_MYJOB = 100;  
  25. #define BUFF_MAX 1 //现在不用到事件里的缓存区,先设定最小值  
  26. struct myevent_s  
  27. {  
  28.     int fd;  
  29.     void (*call_back)(int fd, int events, void *arg);  
  30.     int events;  
  31.     void *arg;  
  32.     int status; // 1: in epoll wait list, 0 not in  
  33.     char buff[BUFF_MAX]; // recv data buffer  
  34.     int len;  
  35.     long last_active; // last active time  
  36. };  
  37.   
  38. //以Socket为关键字的集合.  
  39. std::set<int> m_set;  
  40. //增加锁定。  
  41. mutex m_mxLock;  
  42.   
  43. //把socket插入到集合中,如果存在返回false  
  44. bool  InsertSocket(int nSocket)  
  45. {  
  46.     scopelock lock(m_mxLock);  
  47.     if (m_set.end() == m_set.find(nSocket))  
  48.     {  
  49.         //没有找到插入并返回false;  
  50.         m_set.insert(nSocket);  
  51.         return true;  
  52.     }  
  53.     else  
  54.     {  
  55.         //已经存在不插入返回false  
  56.         return false;  
  57.     }  
  58. }  
  59. //重集合中删除socket;  
  60. bool  EraseSocket(int nSocket)  
  61. {  
  62.     scopelock lock(m_mxLock);  
  63.     //如果集合中存在socket,把Socket从集合里删除  
  64.     if (m_set.end() != m_set.find(nSocket))  
  65.     {  
  66.         //找到再删除;  
  67.         m_set.erase(nSocket);  
  68.         return true;  
  69.     }  
  70.     else  
  71.     {  
  72.         //不存在不删除  
  73.         return false;  
  74.     }  
  75. }  
  76.   
  77. // set event  
  78. void EventSet(myevent_s *ev, int fd, void (*call_back)(intintvoid*), void *arg)  
  79. {  
  80.     ev->fd = fd;  
  81.     ev->call_back = call_back;  
  82.     ev->events = 0;  
  83.     ev->arg = arg;  
  84.     ev->status = 0;  
  85.     ev->last_active = time(NULL);  
  86. }  
  87. // add/mod an event to epoll  
  88. void EventAdd(int epollFd, int events, myevent_s *ev)  
  89. {  
  90.     struct epoll_event epv = {0, {0}};  
  91.     int op;  
  92.     epv.data.ptr = ev;  
  93.     epv.events = ev->events = events;  
  94.     if(ev->status == 1){  
  95.         op = EPOLL_CTL_MOD;  
  96.     }  
  97.     else{  
  98.         op = EPOLL_CTL_ADD;  
  99.         ev->status = 1;  
  100.     }  
  101.     if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)  
  102.     {  
  103.         printf("Event Add failed[fd=%d], status:%d\n", ev->fd, ev->status);  
  104.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "%s: Event Add failed[fd=%d], status:%d error=%d %s\n",  __func__, ev->fd, ev->status,errno, strerror(errno));  
  105.     }  
  106.     else  
  107.     {  
  108.         printf("Event Add OK[fd=%d]\n", ev->fd);  
  109.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "%s: Event Add OK[fd=%d]\n", __func__,  ev->fd);  
  110.     }  
  111. }  
  112. // delete an event from epoll  
  113. void EventDel(int epollFd, myevent_s *ev)  
  114. {  
  115.     struct epoll_event epv = {0, {0}};  
  116.     if(ev->status != 1) return;  
  117.     epv.data.ptr = ev;  
  118.     ev->status = 0;  
  119.     epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);  
  120. }  
  121. int g_epollFd;  
  122. myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd  
  123. void RecvData(int fd, int events, void *arg);  
  124. void SendData(int fd, int events, void *arg);  
  125. // accept new connections from clients  
  126. void AcceptConn(int fd, int events, void *arg)  
  127. {  
  128.     struct sockaddr_in sin;  
  129.     socklen_t len = sizeof(struct sockaddr_in);  
  130.     int nfd, i;  
  131.     // accept  
  132.     if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)  
  133.     {  
  134.         if(errno != EAGAIN && errno != EINTR)  
  135.         {  
  136.             printf("%s: bad accept", __func__);  
  137.             CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "%s: bad accept error = %d %s", __func__, errno, strerror(errno) );  
  138.         }  
  139.         return;  
  140.     }  
  141.     do  
  142.     {  
  143.         for(i = 0; i < MAX_EVENTS; i++)  
  144.         {  
  145.             if(g_Events[i].status == 0)  
  146.             {  
  147.                 break;  
  148.             }  
  149.         }  
  150.         if(i == MAX_EVENTS)  
  151.         {  
  152.             printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);  
  153.             CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "%s: max connection limit[%d]; error = %d %s", __func__, MAX_EVENTS, errno, strerror(errno) );  
  154.             break;  
  155.         }  
  156.         // set nonblocking  
  157.         if(fcntl(nfd, F_SETFL, O_NONBLOCK) < 0) break;  
  158.         // add a read event for receive data  
  159.         EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);  
  160.         EventAdd(g_epollFd, EPOLLIN|EPOLLET, &g_Events[i]);  
  161.         printf("new conn[%s:%d][time:%d]\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active);  
  162.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "%s: new conn[%s:%d][time:%d]", __func__, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active);  
  163.     }while(0);  
  164. }  
  165. // receive data  
  166. void RecvData(int fd, int events, void *arg)  
  167. {  
  168.     struct myevent_s *ev = (struct myevent_s*)arg;  
  169.     int len;  
  170.     // receive data  
  171.     len = recv(fd, ev->buff, sizeof(ev->buff)-1, 0);    
  172.     CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "%s: recv len:%d", __func__, len);  
  173.     EventDel(g_epollFd, ev);  
  174.     if(len > 0)  
  175.     {  
  176.         ev->len = len;  
  177.         ev->buff[len] = '\0';  
  178.         printf("C[%d]:%s\n", fd, ev->buff);  
  179.         // change to send event  
  180.         EventSet(ev, fd, SendData, ev);  
  181.         EventAdd(g_epollFd, EPOLLOUT|EPOLLET, ev);  
  182.     }  
  183.     else if(len == 0)  
  184.     {  
  185.         close(ev->fd);  
  186.         printf("[fd=%d] closed gracefully.\n", fd);  
  187.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "%s: closed gracefully", __func__);  
  188.     }  
  189.     else  
  190.     {  
  191.         close(ev->fd);  
  192.         printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));  
  193.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "%s: recv[fd=%d] error[%d]:%s", __func__, fd, errno, strerror(errno));  
  194.     }  
  195. }  
  196. // send data  
  197. void SendData(int fd, int events, void *arg)  
  198. {  
  199.     struct myevent_s *ev = (struct myevent_s*)arg;  
  200.     int len;  
  201.     // send data  
  202.     len = send(fd, ev->buff, ev->len, 0);  
  203.     CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "%s: send len:%d", __func__, len);  
  204.     ev->len = 0;  
  205.     EventDel(g_epollFd, ev);  
  206.     if(len > 0)  
  207.     {  
  208.         // change to receive event  
  209.         EventSet(ev, fd, RecvData, ev);  
  210.         EventAdd(g_epollFd, EPOLLIN|EPOLLET, ev);  
  211.     }  
  212.     else  
  213.     {  
  214.         close(ev->fd);  
  215.         printf("send[fd=%d] error[%d]\n", fd, errno);  
  216.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, " %s: send[fd=%d] error[%d]:%s", __func__, fd, errno, strerror(errno));  
  217.     }  
  218. }  
  219.   
  220. void InitListenSocket(int epollFd, short port)  
  221. {  
  222.     int listenFd = socket(AF_INET, SOCK_STREAM, 0);  
  223.     fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking  
  224.     printf("server listen fd=%d/n", listenFd);  
  225.     EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);  
  226.     // add listen socket  
  227.     //EventAdd(epollFd, EPOLLIN|EPOLLET, &g_Events[MAX_EVENTS]);  
  228.     EventAdd(epollFd, EPOLLIN, &g_Events[MAX_EVENTS]);  
  229.     // bind & listen  
  230.     sockaddr_in sin;  
  231.     bzero(&sin, sizeof(sin));  
  232.     sin.sin_family = AF_INET;  
  233.     sin.sin_addr.s_addr = INADDR_ANY;  
  234.     sin.sin_port = htons(port);  
  235.     bind(listenFd, (const sockaddr*)&sin, sizeof(sin));  
  236.     listen(listenFd, SOMAXCONN);  
  237. }  
  238.   
  239. //线程池函数  
  240. class myjobthread: public thread  
  241. {  
  242. protected:  
  243.     int id;  
  244.     jobqueue* jq;  
  245.     virtual void execute();  
  246. public:  
  247.     myjobthread(int iid, jobqueue* ijq)  
  248.         : thread(false), id(iid), jq(ijq)  {}  
  249.     ~myjobthread()  { waitfor(); }  
  250. };  
  251.   
  252. class myjob: public message  
  253. {  
  254. public:  
  255.     myevent_s* m_pSocketInfo;  
  256.     myjob(myevent_s* pSocketInfo)  
  257.         : message(MSG_MYJOB), m_pSocketInfo(pSocketInfo)  {}  
  258.     ~myjob()    
  259.     {  
  260.         //delete m_pSocketInfo;  
  261.     }  
  262. };  
  263.   
  264.   
  265. void myjobthread::execute()  
  266. {  
  267.     bool quit = false;  
  268.     while (!quit)  
  269.     {  
  270.         // get the next message from the queue  
  271.         message* msg = jq->getmessage();  
  272.   
  273.         try  
  274.         {  
  275.             switch (msg->id)  
  276.             {  
  277.             case MSG_MYJOB:  
  278.                 {  
  279.                     pout.putf("%t,线程:%d\n", now(), id);  
  280.                       
  281.   
  282.                     myevent_s *ev = ((myjob*)msg)->m_pSocketInfo;  
  283.                     if(ev->events&EPOLLIN) // read event  
  284.                     {  
  285.                         ev->call_back(ev->fd, ev->events, ev->arg);  
  286.                     }  
  287.                     if(ev->events&EPOLLOUT) // write event  
  288.                     {  
  289.                         ev->call_back(ev->fd, ev->events, ev->arg);  
  290.                     }  
  291.   
  292.   
  293.                     //pout.putf("%t,%d返回:%d字节\n",now(), id, nSend);  
  294.   
  295.                 }  
  296.                 break;  
  297.   
  298.             case MSG_QUIT:  
  299.                 // MSG_QUIT is not used in our example  
  300.                 quit = true;  
  301.                 break;  
  302.             }  
  303.         }  
  304.         catch(pt::exception*)  
  305.         {  
  306.             // the message object must be freed!  
  307.             delete msg;  
  308.             throw;  
  309.         }  
  310.         delete msg;  
  311.     }  
  312. }  
  313.   
  314. int main(int argc, char **argv)  
  315. {  
  316.     short port = 8108; // default port  
  317.     if(argc == 2){  
  318.         port = atoi(argv[1]);  
  319.     }  
  320.   
  321.     CLogFile::Instance()->LOG_Start("./log/");  
  322.   
  323.     //启动线程池  
  324.     jobqueue jq;  
  325.     tobjlist<myjobthread> threads(true);  
  326.   
  327.     // create the thread pool  
  328.     for(int n = 0; n < maxthreads; n++)  
  329.     {  
  330.         myjobthread* j = new myjobthread(n + 1, &jq);  
  331.         j->start();  
  332.         threads.add(j);  
  333.     }  
  334.   
  335.     // create epoll  
  336.     g_epollFd = epoll_create(MAX_EVENTS);  
  337.     if(g_epollFd <= 0)   
  338.     {  
  339.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "create epoll failed.");  
  340.         printf("create epoll failed.%d\n", g_epollFd);  
  341.     }  
  342.     // create & bind listen socket, and add to epoll, set non-blocking  
  343.     InitListenSocket(g_epollFd, port);  
  344.     // event loop  
  345.     struct epoll_event events[MAX_EVENTS];  
  346.     printf("server running:port[%d]\n", port);  
  347.     int checkPos = 0;  
  348.     while(1)  
  349.     {  
  350.         // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event  
  351.         long now = time(NULL);  
  352.         for(int k = 0; k < MAX_EVENTS; k++, checkPos++) // doesn't check listen fd  
  353.         {  
  354.             if(checkPos == MAX_EVENTS) checkPos = 0; // recycle  
  355.             if(g_Events[checkPos].status != 1) continue;  
  356.             long duration = now - g_Events[checkPos].last_active;  
  357.             if(duration >= 600) // 600s timeout  
  358.             {  
  359.                 closesocket(g_Events[checkPos].fd);  
  360.                 printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);  
  361.                 CLogFile::Instance()->LOG_WriteLine(LOG_INFO_WARN, "超时Socket:[fd=%d] timeout[%d--%d].", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);  
  362.                 EventDel(g_epollFd, &g_Events[checkPos]);  
  363.             }  
  364.         }  
  365.         // wait for events to happen  
  366.   
  367.         int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, -1);  
  368.   
  369.         if(fds < 0)  
  370.         {  
  371.             printf("epoll_wait error, exit/n");  
  372.             CLogFile::Instance()->LOG_WriteLine(LOG_INFO_ERROR, "epoll_wait error.");  
  373.             break;  
  374.         }  
  375.         CLogFile::Instance()->LOG_WriteLine(LOG_INFO_HIT, "EPOLL_WAIT FDS counts:%d", fds);  
  376.         for(int i = 0; i < fds; i++)  
  377.         {  
  378.             myevent_s *ev = (struct myevent_s*)events[i].data.ptr;  
  379.             jq.post(new myjob(ev));  
  380.   
  381.         }  
  382.     }  
  383.     // free resource  
  384.     return 0;  
  385. }  


 

0 0
原创粉丝点击