epoll的一个demo,备忘

epoll的一个demo,备忘

关键字: epoll demo

C代码
  1. /**  
  2. 张亚霏修改  
  3.  
  4. 文件名:epoll_demo.c  
  5. 编译: gcc epoll_demo.c -pthread  
  6.  
  7.  
  8. 程序源码如下(请自行编辑宏定义SERVER_IP为自己的IP):  
  9. */  
  10.   
  11.   
  12. /*Linux 2.6 x86_64 only*/  
  13.   
  14. #include    
  15. #include    
  16. #include    
  17.   
  18. #include    
  19. #include    
  20. #include    
  21. #include    
  22. #include    
  23. #include    
  24. #include    
  25. #include    
  26. #include    
  27. #include    
  28. #include    
  29.   
  30. /*线程池的线程数量*/  
  31. #define THREAD_MAX 1   
  32.   
  33. /*监听端口*/  
  34. #define LISTEN_PORT 8000   
  35.   
  36. /*  
  37. 监听端口的数量,从LISTEN_PORT到LISTEN_PORT+LISTEN_MAX-1  
  38. */  
  39. #define LISTEN_MAX 1   
  40.   
  41.   
  42. #define SERVER_IP "127.0.0.1"   
  43.   
  44.   
  45. typedef struct  
  46. {   
  47.     char    ip4[128];   
  48.     int     port;   
  49.     int     fd;   
  50. } listen_info;   
  51.   
  52.   
  53.   
  54. //服务器参数   
  55. static listen_info s_listens[LISTEN_MAX];   
  56.   
  57. //线程池参数   
  58. static unsigned int s_thread_para[THREAD_MAX][8];//线程参数   
  59. static pthread_t s_tid[THREAD_MAX];//线程ID   
  60. pthread_mutex_t s_mutex[THREAD_MAX];//线程锁   
  61.   
  62.   
  63. //私有函数   
  64. static int init_thread_pool(void);   
  65. static int init_listen4(char *ip4, int port, int max_link);   
  66.   
  67. //线程函数   
  68. void* test_server4(unsigned int thread_para[]);   
  69.   
  70. int main(int argc, char *argv[])//客户端驱动   
  71. {   
  72.     //临时变量   
  73.     int            i, j, rc;   
  74.   
  75.     int            sock_listen;    //监听套接字   
  76.     int            sock_cli;    //客户端连接   
  77.     int            listen_index;   
  78.   
  79.     int            epfd;   
  80.     int         nfds;   
  81.     struct epoll_event    ev;   
  82.     struct epoll_event    events[LISTEN_MAX];   
  83.   
  84.     socklen_t        addrlen;    //地址信息长度   
  85.     struct sockaddr_in    addr4;        //IPv4地址结构   
  86.   
  87.   
  88.   
  89.   
  90.     //线程池初始化   
  91.     rc = init_thread_pool();   
  92.     if (0 != rc)   
  93.     exit(-1);   
  94.   
  95.     //初始化服务监听   
  96.     for (i = 0; i < LISTEN_MAX; i++)   
  97.     {   
  98.         sprintf(s_listens[i].ip4, "%s", SERVER_IP);   
  99.         s_listens[i].port = LISTEN_PORT + i;   
  100.         //创建监听   
  101.         rc = init_listen4(s_listens[i].ip4, s_listens[i].port, 64);   
  102.         if (0 > rc)   
  103.         {   
  104.             fprintf(stderr, "无法创建服务器监听于%s:%d/n", s_listens[i].ip4, s_listens[i].port);   
  105.             perror(NULL);   
  106.             exit(-1);   
  107.         }   
  108.         s_listens[i].fd = rc;   
  109.     }   
  110.   
  111.     //设置集合   
  112.     epfd = epoll_create(8192);   
  113.     for (i = 0; i < LISTEN_MAX; i++)   
  114.     {   
  115.         //加入epoll事件集合   
  116.         ev.events = EPOLLIN;   
  117.         ev.data.u32 = i;//记录listen数组下标   
  118.         if (epoll_ctl(epfd, EPOLL_CTL_ADD, s_listens[i].fd, &ev) < 0)   
  119.         {   
  120.             fprintf(stderr, "向epoll集合添加套接字失败(fd =%d)/r/n", rc);   
  121.             exit(-1);   
  122.         }   
  123.     }   
  124.   
  125.   
  126.     //服务循环   
  127.     for ( ; ; )   
  128.     {   
  129.         //等待epoll事件   
  130.         nfds = epoll_wait(epfd, events, LISTEN_MAX, -1);   
  131.         //处理epoll事件   
  132.         for (i = 0; i < nfds; i++)   
  133.         {   
  134.             //接收客户端连接   
  135.             listen_index = events[i].data.u32;   
  136.             sock_listen = s_listens[listen_index].fd;   
  137.             addrlen = sizeof(struct sockaddr_in);   
  138.             bzero(&addr4, addrlen);   
  139.             sock_cli = accept(sock_listen, (struct sockaddr *)&addr4, &addrlen);   
  140.             if (0 > sock_cli)   
  141.             {   
  142.                 fprintf(stderr, "接收客户端连接失败/n");   
  143.                 continue;   
  144.             }   
  145.             //查询空闲线程对   
  146.             for (j = 0; j < THREAD_MAX; j++)   
  147.             {   
  148.                 if (0 == s_thread_para[j][0]) break;   
  149.             }   
  150.             if (j >= THREAD_MAX)   
  151.             {   
  152.                 fprintf(stderr, "线程池已满, 连接将被放弃/r/n");   
  153.                 shutdown(sock_cli, SHUT_RDWR);   
  154.                 close(sock_cli);   
  155.                 continue;   
  156.             }   
  157.             //复制有关参数   
  158.             s_thread_para[j][0] = 1;//设置活动标志为"活动"   
  159.             s_thread_para[j][1] = sock_cli;//客户端连接   
  160.             s_thread_para[j][2] = listen_index;//服务索引   
  161.             //线程解锁   
  162.             pthread_mutex_unlock(s_mutex + j);   
  163.         }//end of for(i;;)   
  164.     }//end of for(;;)   
  165.   
  166.     exit(0);   
  167. }   
  168.   
  169. static int init_thread_pool(void)   
  170. {   
  171.     int    i, rc;   
  172.   
  173.     //初始化线程池参数   
  174.     for (i = 0; i < THREAD_MAX; i++)   
  175.     {   
  176.         s_thread_para[i][0] = 0;//设置线程占用标志为"空闲"   
  177.         s_thread_para[i][7] = i;//线程池索引   
  178.         pthread_mutex_lock(s_mutex + i);//线程锁   
  179.     }   
  180.   
  181.     //创建线程池   
  182.     for (i = 0; i < THREAD_MAX; i++)   
  183.     {   
  184.         rc = pthread_create(s_tid + i, 0, (void *)test_server4, (void *)(s_thread_para[i]));   
  185.         if (0 != rc)   
  186.         {   
  187.             fprintf(stderr, "线程创建失败/n");   
  188.             return(-1);   
  189.         }   
  190.     }   
  191.   
  192.     //成功返回   
  193.     return(0);   
  194. }   
  195.   
  196. static int init_listen4(char *ip4, int port, int max_link)   
  197. {   
  198.     //临时变量   
  199.     int            sock_listen4;   
  200.     struct sockaddr_in    addr4;   
  201.     unsigned int        optval;   
  202.     struct linger        optval1;   
  203.   
  204.     //初始化数据结构   
  205.     bzero(&addr4, sizeof(addr4));   
  206.     inet_pton(AF_INET, ip4, &(addr4.sin_addr));   
  207.     addr4.sin_family = AF_INET;   
  208.     addr4.sin_port = htons(port);   
  209.   
  210.     //创建SOCKET   
  211.     sock_listen4 = socket(AF_INET, SOCK_STREAM, 0);   
  212.     if (0 > sock_listen4) return(-1);   
  213.   
  214.     //设置SO_REUSEADDR选项(服务器快速重起)   
  215.     optval = 0x1;   
  216.     setsockopt(sock_listen4, SOL_SOCKET, SO_REUSEADDR, &optval, 4);   
  217.   
  218.     //设置SO_LINGER选项(防范CLOSE_WAIT挂住所有套接字)   
  219.     optval1.l_onoff = 1;   
  220.     optval1.l_linger = 60;   
  221.     setsockopt(sock_listen4, SOL_SOCKET, SO_LINGER, &optval1, sizeof(struct linger));   
  222.   
  223.     if (0 > bind(sock_listen4, (struct sockaddr *)&addr4, sizeof(addr4)))   
  224.     {   
  225.         close(sock_listen4);   
  226.         return(-1);   
  227.     }   
  228.   
  229.     if (0 > listen(sock_listen4, max_link))   
  230.     {   
  231.         close(sock_listen4);   
  232.         return(-1);   
  233.     }   
  234.   
  235.     return(sock_listen4);   
  236. }   
  237.   
  238.   
  239. void * test_server4(unsigned int thread_para[])   
  240. {   
  241.     //临时变量   
  242.     int        pool_index;    //线程池索引   
  243.     int        sock_cli;    //客户端连接   
  244.     int        listen_index;    //监听索引   
  245.   
  246.     char        buff[32768];    //传输缓冲区   
  247.     char        *p;   
  248.     int        i, j, len;   
  249.   
  250.     //线程脱离创建者   
  251.     pthread_detach(pthread_self());   
  252.     pool_index = thread_para[7];   
  253.   
  254. wait_unlock:   
  255.   
  256.     pthread_mutex_lock(s_mutex + pool_index);//等待线程解锁   
  257.   
  258.     //线程变量内容复制   
  259.     sock_cli = thread_para[1];//客户端连接   
  260.     listen_index = thread_para[2];//监听索引   
  261.   
  262.     //接收请求   
  263.     len = recv(sock_cli, buff, 32768, MSG_NOSIGNAL);   
  264.   
  265.     //构造响应   
  266.     p = buff;   
  267.     //HTTP头   
  268.     p += sprintf(p, "HTTP/1.1 200 OK/r/n");   
  269.     p += sprintf(p, "Content-Type: text/html/r/n");   
  270.     p += sprintf(p, "Connection: closed/r/n/r/n");   
  271.     //页面   
  272.     p += sprintf(p, "/r/n/r/n");   
  273.     p += sprintf(p, "/r/n");   
  274.     p += sprintf(p, "/r/n");   
  275.     p += sprintf(p, "/r/n");   
  276.   
  277.     p += sprintf(p, "
    /r/n");   
  278.     p += sprintf(p, "

    连接状态

    /r/n"
    );   
  279.     p += sprintf(p, "

    服务器地址 %s:%d

    /r/n"
    , s_listens[listen_index].ip4, s_listens[listen_index].port);   
  280.     j = 0;   
  281.     for (i = 0; i < THREAD_MAX; i++)   
  282.     {   
  283.         if (0 != s_thread_para[i][0]) j++;   
  284.     }   
  285.     p += sprintf(p, "

    线程池状态

    /r/n"
    );   
  286.     p += sprintf(p, "

    线程池总数 %d 活动线程总数 %d

    /r/n"
    , THREAD_MAX, j);   
  287.     p += sprintf(p, "/r/n");   
  288.     len = p - buff;   
  289.   
  290.     //发送响应   
  291.     send(sock_cli, buff, len, MSG_NOSIGNAL);   
  292.   
  293.     //释放连接   
  294.     shutdown(sock_cli, SHUT_RDWR);   
  295.     close(sock_cli);   
  296.   
  297.     //线程任务结束   
  298.     thread_para[0] = 0;//设置线程占用标志为"空闲"   
  299.     goto wait_unlock;   
  300.   
  301.     pthread_exit(NULL);   
  302. }  

你可能感兴趣的:(linux多进程/线程)