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 <stdio.h>   
  15. #include <stdlib.h>   
  16. #include <string.h>   
  17.   
  18. #include <time.h>   
  19. #include <sys/epoll.h>   
  20. #include <sys/stat.h>   
  21. #include <sys/types.h>   
  22. #include <sys/socket.h>   
  23. #include <netinet/in.h>   
  24. #include <arpa/inet.h>   
  25. #include <unistd.h>   
  26. #include <netdb.h>   
  27. #include <pthread.h>   
  28. #include <errno.h>   
  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, "<html>/r/n<head>/r/n");   
  273.     p += sprintf(p, "<meta content=/"text/html; charset=GBK/" http-equiv=/"Content-Type/">/r/n");   
  274.     p += sprintf(p, "</head>/r/n");   
  275.     p += sprintf(p, "<body style=/"background-color: rgb(229, 229, 229);/">/r/n");   
  276.   
  277.     p += sprintf(p, "<center>/r/n");   
  278.     p += sprintf(p, "<H3>连接状态</H3>/r/n");   
  279.     p += sprintf(p, "<p>服务器地址 %s:%d</p>/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, "<H3>线程池状态</H3>/r/n");   
  286.     p += sprintf(p, "<p>线程池总数 %d 活动线程总数 %d</p>/r/n", THREAD_MAX, j);   
  287.     p += sprintf(p, "</center></body></html>/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. }  
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里是一个简单的 epoll 例子: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <arpa/inet.h> #include <sys/epoll.h> #define MAX_EVENTS 10 int main(int argc, char *argv[]) { int listen_sock, conn_sock, epoll_fd, nfds, i, n; struct sockaddr_in serv_addr, cli_addr; socklen_t cli_len = sizeof(cli_addr); struct epoll_event ev, events[MAX_EVENTS]; char buffer[1024]; if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(EXIT_FAILURE); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(8080); if (bind(listen_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("bind"); exit(EXIT_FAILURE); } if (listen(listen_sock, SOMAXCONN) < 0) { perror("listen"); exit(EXIT_FAILURE); } if ((epoll_fd = epoll_create1(0)) < 0) { perror("epoll_create1"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = listen_sock; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_sock, &ev) < 0) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } while (1) { nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds < 0) { perror("epoll_wait"); exit(EXIT_FAILURE); } for (i = 0; i < nfds; ++i) { if (events[i].data.fd == listen_sock) { conn_sock = accept(listen_sock, (struct sockaddr *) &cli_addr, &cli_len); if (conn_sock < 0) { perror("accept"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = conn_sock; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_sock, &ev) < 0) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { n = read(events[i].data.fd, buffer, sizeof(buffer)); if (n < 0) { perror("read"); exit(EXIT_FAILURE); } if (n == 0) { if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL) < 0) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } close(events[i].data.fd); } else { if (write(events[i].data.fd, buffer, n) < 0) { perror("write"); exit(EXIT_FAILURE); } } } } } return 0; } ``` 这个程序监听端口 8080,并使用 epoll 实现一个简单的回显服务器。它可以同时处理多个连接,当有新连接到来时,将其加入 epoll 监听队列中,当某个连接的数据可读时,就读取并回显给客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值