Nginx网络epoll多进程系列:tcp服务器仿nginx多进程和多路IO的实现

http://blog.csdn.net/ypbsyy/article/details/38046267

1、服务端代码,开启8个工作进程

[objc]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <signal.h>  
  5. #include <sys/epoll.h>  
  6. #include <unistd.h>  
  7. #include <sys/socket.h>  
  8. #include <sys/types.h>  
  9. #include <netinet/in.h>  
  10. #include <fcntl.h>  
  11. #include <sys/mman.h>  
  12. #include <pthread.h>  
  13. #include <errno.h>   
  14. #include <unistd.h>  
  15.   
  16. #define WORKER_MAX        1024  
  17. #define EVENT_LIST_MAX    128  
  18. #define EVENT_MAX         12  
  19. #define WORK_REAL         8  
  20. #define SERVER_PORT       8080   
  21.   
  22. static int workers[WORKER_MAX];  
  23. static int icEpollFd = -1;  
  24. static int cur_pid;  
  25.   
  26. typedef int (*PFCALLBACL)(struct epoll_event *);  
  27. typedef struct EPOLL_DATA_S  
  28. {  
  29.     int iEpoll_Fd;  
  30.     int iEvent_Fd;  
  31.     PFCALLBACL pfCallBack;  
  32. }Epoll_Data_S;  
  33.   
  34. /* 互斥量 */  
  35. static pthread_mutex_t *mutex;  
  36.   
  37. /* 创建共享的mutex */  
  38. static void initMutex(void)  
  39. {  
  40.     pthread_mutexattr_t attr;  
  41.     int ret;  
  42.       
  43.     //设置互斥量为进程间共享  
  44.     mutex=(pthread_mutex_t*)mmap(NULLsizeof(pthread_mutex_t), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -10);  
  45.     if( MAP_FAILED==mutex) {  
  46.         perror("mutex mmap failed");  
  47.         return;  
  48.     }  
  49.       
  50.     //设置attr的属性  
  51.     pthread_mutexattr_init(&attr);  
  52.     ret = pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);  
  53.     if(ret != 0) {  
  54.         fprintf(stderr, "mutex set shared failed");  
  55.         return;  
  56.     }  
  57.     pthread_mutex_init(mutex, &attr);  
  58.   
  59.     return;  
  60. }  
  61.   
  62. static int startup(unsigned short port)  
  63. {  
  64.     struct sockaddr_in servAddr;  
  65.     unsigned value = 1;  
  66.     int listenFd;  
  67.   
  68.     memset(&servAddr, 0sizeof(servAddr));  
  69.       
  70.     //协议域(ip地址和端口)  
  71.     servAddr.sin_family = AF_INET;  
  72.       
  73.     //绑定默认网卡  
  74.     servAddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  75.       
  76.     //端口  
  77.     servAddr.sin_port = htons(port);  
  78.       
  79.     //创建套接字  
  80.     if ((listenFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
  81.         printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);  
  82.         return 0;  
  83.     }  
  84.       
  85.     setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));  
  86.       
  87.     //绑定套接字  
  88.     if (bind(listenFd, (struct sockaddr *)&servAddr, sizeof(servAddr))) {  
  89.         printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);  
  90.         return 0;  
  91.     }  
  92.     //开始监听,设置最大连接请求  
  93.     if (listen(listenFd, 10) == -1) {  
  94.         printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);  
  95.         return 0;  
  96.     }  
  97.       
  98.     return listenFd;  
  99. }  
  100.   
  101. static int create_workers(unsigned int worker_num)  
  102. {  
  103.     unsigned int i;  
  104.     unsigned int real_num = worker_num;  
  105.     int pid;  
  106.   
  107.     if (real_num > WORKER_MAX)  
  108.     {  
  109.         real_num = WORKER_MAX;  
  110.     }  
  111.   
  112.     for (i = 0; i < real_num; i++)  
  113.     {  
  114.         pid = fork();  
  115.         if (0 == pid)  
  116.         {  
  117.             return 0;  
  118.         }  
  119.         else if (0 < pid)  
  120.         {  
  121.             workers[i] = pid;  
  122.             continue;  
  123.         }  
  124.         else  
  125.         {  
  126.             printf("fork error\r\n");  
  127.             return 0;  
  128.         }  
  129.     }  
  130.   
  131.     return 1;  
  132. }  
  133.   
  134. /* 创建epoll */  
  135. static int create_epoll(unsigned int event_num)  
  136. {  
  137.     int epoll_fd;  
  138.   
  139.     epoll_fd = epoll_create(event_num);  
  140.     if (-1 == epoll_fd)  
  141.     {  
  142.         printf("epoll create failed\r\n");  
  143.         return -1;  
  144.     }  
  145.   
  146.     return epoll_fd;  
  147. }  
  148.   
  149. /* 将事件加到epoll */  
  150. static void add_event_epoll(int iEpoll_Fd, int iEvent_Fd, PFCALLBACL pfCallBack)  
  151. {  
  152.     int                  op = EPOLL_CTL_ADD;  
  153.     struct epoll_event   ee;  
  154.     Epoll_Data_S *data;  
  155.   
  156.     data = malloc(sizeof(Epoll_Data_S));  
  157.     if (NULL == data)  
  158.     {  
  159.         return;  
  160.     }  
  161.   
  162.     /* 设置私有数据 */  
  163.     data->iEpoll_Fd = iEpoll_Fd;  
  164.     data->iEvent_Fd = iEvent_Fd;  
  165.     data->pfCallBack = pfCallBack;  
  166.   
  167.     ee.events = EPOLLIN | EPOLLOUT | EPOLLHUP;  
  168.     //ee.events = EPOLLIN|EPOLLET;  
  169.     ee.data.ptr = (voidvoid *)data;  
  170.   
  171.     if (epoll_ctl(iEpoll_Fd, op, iEvent_Fd, &ee) == -1)   
  172.     {  
  173.         printf("epoll_ctl(%d, %d) failed", op, iEvent_Fd);  
  174.         return;  
  175.     }  
  176.       
  177.     return;  
  178. }  
  179.   
  180. /* 从epoll删除事件 */  
  181. static void del_event_epoll(int iEpoll_Fd, int iEvent_Fd)  
  182. {  
  183.     int op = EPOLL_CTL_DEL;  
  184.       
  185.     if (epoll_ctl(iEpoll_Fd, op, iEvent_Fd, NULL) == -1)   
  186.     {  
  187.         printf("epoll_ctl(%d, %d) failed", op, iEvent_Fd);  
  188.     }  
  189.   
  190.     return;  
  191. }  
  192.   
  193. static int make_socket_non_blocking(int fd)  
  194. {  
  195.   int flags, s;  
  196.   
  197.   flags = fcntl (fd, F_GETFL, 0);  
  198.   if (flags == -1)  
  199.     {  
  200.       perror ("fcntl");  
  201.       return -1;  
  202.     }  
  203.   
  204.   flags |= O_NONBLOCK;  
  205.   s = fcntl (fd, F_SETFL, flags);  
  206.   if (s == -1)  
  207.     {  
  208.       perror ("fcntl");  
  209.       return -1;  
  210.     }  
  211.   
  212.   return 0;  
  213. }  
  214.   
  215. /* 处理Receive事件 */  
  216. static int proc_receive(struct epoll_event *pstEvent)  
  217. {  
  218.     char buff[4096];   /* 缓存 */  
  219.     int len;  
  220.     Epoll_Data_S *data = (Epoll_Data_S *)(pstEvent->data.ptr);  
  221.     int iEpoll_Fd = data->iEpoll_Fd;  
  222.     int iEvent_Fd = data->iEvent_Fd;  
  223.       
  224.     if (pstEvent->events & EPOLLIN)  
  225.     {  
  226.         while(1)  
  227.         {  
  228.             /* 读取数据 */  
  229.             len = (int)recv(iEvent_Fd, buff, sizeof(buff), 0);    
  230.             //printf("proc_receive iEvent_Fd = %d pid = %d len = %d\r\n", iEvent_Fd, getpid(), len);  
  231.             if (len <= 0)   
  232.             {  
  233.                 if (errno == EINTR)  
  234.                 {  
  235.                    continue;  
  236.                 }  
  237.                   
  238.                 del_event_epoll(iEpoll_Fd, iEvent_Fd);  
  239.                 close(iEvent_Fd);   
  240.                 free(data);  
  241.             }  
  242.             else if (len > 0)  
  243.             {    
  244.                 buff[len] = '\0';    
  245.                 printf("pid %d receive data: %s\r\n", cur_pid, buff);  
  246.                 //usleep(10000);  
  247.             }  
  248.   
  249.             break;  
  250.         }  
  251.     }  
  252.     else if (pstEvent->events & EPOLLHUP)  
  253.     {  
  254.         printf("receive EPOLLHUP or EPOLLOUT\r\n");  
  255.           
  256.         del_event_epoll(iEpoll_Fd, iEvent_Fd);  
  257.         close(iEvent_Fd);  
  258.         free(data);  
  259.     }  
  260.     else  
  261.     {  
  262.        // printf("receive others pstEvent->events=%d\r\n", pstEvent->events);  
  263.     }  
  264.       
  265.     return 0;  
  266. }  
  267.   
  268. /* 处理Accept事件 */  
  269. static int proc_accept(struct epoll_event *pstEvent)  
  270. {  
  271.     int newFd;  
  272.     Epoll_Data_S *data = (Epoll_Data_S *)(pstEvent->data.ptr);  
  273.     int iEpoll_Fd = data->iEpoll_Fd;  
  274.     int iEvent_Fd = data->iEvent_Fd;  
  275.       
  276.     if (pthread_mutex_trylock(mutex)==0)   
  277.     {  
  278.         while(-1 != (newFd = accept(iEvent_Fd, (struct sockaddr *)NULLNULL)))  
  279.         {  
  280.             make_socket_non_blocking(newFd);  
  281.             //printf("accept pid = %d\r\n", getpid());  
  282.             add_event_epoll(icEpollFd, newFd, proc_receive);  
  283.         }  
  284.   
  285.         pthread_mutex_unlock(mutex);  
  286.     }  
  287.   
  288.     return 0;  
  289. }  
  290.   
  291. static void handleterm(int sig)  
  292. {  
  293.     int i;  
  294.   
  295.     for (i = 0; i < WORK_REAL; i++)  
  296.     {  
  297.         /* 杀掉子进程 */  
  298.         kill(workers[i], SIGTERM);  
  299.     }  
  300.       
  301.     return;  
  302. }  
  303.   
  304. static void proc_epoll(int iEpollFd, int timeout)  
  305. {  
  306.     int iEventNum;  
  307.     int i;  
  308.     struct epoll_event events[EVENT_LIST_MAX];  
  309.       
  310.     iEventNum = epoll_wait(iEpollFd, events, EVENT_LIST_MAX, timeout);  
  311.     for (i = 0; i < iEventNum; i++)  
  312.     {  
  313.         Epoll_Data_S *data = (Epoll_Data_S *)(events[i].data.ptr);  
  314.         data->pfCallBack(&(events[i]));  
  315.     }  
  316.   
  317.     return;  
  318. }  
  319.   
  320. int main()  
  321. {  
  322.     int iServerFd = -1;  
  323.     int bParent;  
  324.     int iEpollFd = -1;  
  325.   
  326.     /* 初始化互斥量 */  
  327.     initMutex();  
  328.       
  329.     /* 初始化,创建监听端口 */  
  330.     iServerFd = startup(SERVER_PORT);  
  331.     if (-1 == iServerFd)  
  332.     {  
  333.         return 0;  
  334.     }  
  335.   
  336.     make_socket_non_blocking(iServerFd);  
  337.   
  338.     /* 父进程创建epoll */  
  339.     iEpollFd = create_epoll(EVENT_MAX);  
  340.     if (-1 == iEpollFd)  
  341.     {  
  342.         close(iServerFd);  
  343.         return 0;  
  344.     }  
  345.   
  346.     /* 将监听端口加到epoll */  
  347.     add_event_epoll(iEpollFd, iServerFd, proc_accept);  
  348.   
  349.     /* 创建子进程  */  
  350.     bParent = create_workers(WORK_REAL);  
  351.   
  352.     /* 主进程 */  
  353.     if (bParent)  
  354.     {  
  355.         while(1)  
  356.         {  
  357.             signal(SIGTERM, handleterm);  
  358.             pause();  
  359.         }  
  360.     }  
  361.     else  
  362.     {  
  363.           /* 子进程创建epoll */  
  364.           icEpollFd = create_epoll(EVENT_MAX);      
  365.           if (-1 == icEpollFd)  
  366.           {  
  367.              close(iServerFd);  
  368.              return 0;  
  369.           }  
  370.   
  371.           cur_pid = getpid();  
  372.    
  373.           while (1)  
  374.           {  
  375.             /* 处理父epoll消息 */  
  376.             proc_epoll(iEpollFd, 50);  
  377.   
  378.             /* 处理子epoll消息 */  
  379.             proc_epoll(icEpollFd, 50);  
  380.         }  
  381.     }  
  382.   
  383.     return 0;  
  384. }  

2、客户端代码,发起高并发连接,暂定连接数为2000,可以自己调

[objc]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <string.h>  
  5. #include <netdb.h>  
  6. #include <sys/socket.h>  
  7. #include <netinet/in.h>  
  8. #include<arpa/inet.h>  
  9. #include <fcntl.h>  
  10. #include <errno.h>  
  11.   
  12. const int MAXLINE = 5;  
  13. int count = 1;  
  14.   
  15. static int make_socket_non_blocking(int fd)  
  16. {  
  17.   int flags, s;  
  18.   
  19.   flags = fcntl (fd, F_GETFL, 0);  
  20.   if (flags == -1)  
  21.     {  
  22.       perror ("fcntl");  
  23.       return -1;  
  24.     }  
  25.   
  26.   flags |= O_NONBLOCK;  
  27.   s = fcntl (fd, F_SETFL, flags);  
  28.   if (s == -1)  
  29.     {  
  30.       perror ("fcntl");  
  31.       return -1;  
  32.     }  
  33.   
  34.   return 0;  
  35. }  
  36.   
  37. void sockconn()  
  38. {  
  39.     int sockfd;  
  40.     struct sockaddr_in server_addr;  
  41.     struct hostent *host;  
  42.     char buf[100];  
  43.     unsigned int value = 1;  
  44.   
  45.     host = gethostbyname("127.0.0.1");  
  46.     sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  47.     if (sockfd == -1) {  
  48.         perror("socket error\r\n");  
  49.         return;  
  50.     }  
  51.       
  52.     //setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));  
  53.       
  54.     //make_socket_non_blocking(sockfd);  
  55.   
  56.     bzero(&server_addr, sizeof(server_addr));  
  57.   
  58.     server_addr.sin_family = AF_INET;  
  59.     server_addr.sin_port = htons(8080);  
  60.     server_addr.sin_addr = *((struct in_addr*) host->h_addr);  
  61.   
  62.     int cn = connect(sockfd, (struct sockaddr *) &server_addr,  
  63.             sizeof(server_addr));  
  64.     if (cn == -1) {  
  65.         printf("connect error errno=%d\r\n", errno);  
  66.         return;  
  67.   
  68.     }  
  69. //  char *buf = "h";  
  70.     sprintf(buf, "%d", count);  
  71.     count++;  
  72.     write(sockfd, buf, strlen(buf));  
  73.     close(sockfd);  
  74.       
  75.     printf("client send %s\r\n", buf);  
  76.       
  77.     return;  
  78. }  
  79.   
  80. int main(void) {  
  81.    
  82.  int i;  
  83.  for (i = 0; i < 2000; i++)  
  84.  {  
  85.       sockconn();  
  86.  }  
  87.    
  88.  return 0;  
  89. }  

3、测试结果

1秒多时间内,处理了2000个连接

[plain]  view plain  copy
  1. 4、需要注意的问题连接太多时,open files too many问题  
[plain]  view plain  copy
  1. localhost:/share/code # ulimit -a  
  2. core file size          (blocks, -c) 0  
  3. data seg size           (kbytes, -d) unlimited  
  4. scheduling priority             (-e) 0  
  5. file size               (blocks, -f) unlimited  
  6. pending signals                 (-i) 7900  
  7. max locked memory       (kbytes, -l) 64  
  8. max memory size         (kbytes, -m) 865300  
  9. open files                      (-n) 1024  
  10. pipe size            (512 bytes, -p) 8  
  11. POSIX message queues     (bytes, -q) 819200  
  12. real-time priority              (-r) 0  
  13. stack size              (kbytes, -s) 8192  
  14. cpu time               (seconds, -t) unlimited  
  15. max user processes              (-u) 7900  
  16. virtual memory          (kbytes, -v) 2491600  
  17. file locks                      (-x) unlimited  
  18. localhost:/share/code #   

解决方法:

[sql]  view plain  copy
  1. localhost:/share/code # ulimit -n 100000  
  2. localhost:/share/code # ulimit -a  
  3. core file size          (blocks, -c) 0  
  4. data seg size           (kbytes, -d) unlimited  
  5. scheduling priority             (-e) 0  
  6. file size               (blocks, -f) unlimited  
  7. pending signals                 (-i) 7900  
  8. max locked memory       (kbytes, -l) 64  
  9. max memory size         (kbytes, -m) 865300  
  10. open files                      (-n) 100000  
  11. pipe size            (512 bytes, -p) 8  
  12. POSIX message queues     (bytes, -q) 819200  
  13. real-time priority              (-r) 0  
  14. stack size              (kbytes, -s) 8192  
  15. cpu time               (seconds, -t) unlimited  
  16. max user processes              (-u) 7900  
  17. virtual memory          (kbytes, -v) 2491600  
  18. file locks                      (-x) unlimited  
  19. localhost:/share/code #   

2)客户端connect错误

原因:处于TIME-WAIT状态的socket太多,socket不够用

解决:减少TIME-WAIT时间

[plain]  view plain  copy
  1. localhost:/share/code # echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle   
  2. localhost:/share/code # echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse   
  3. localhost:/share/code #   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值