多进程服务器中,epoll的创建应该在创建子进程之后

news/2024/7/20 9:14:09 标签: 服务器, events, socket, linux内核, stream, null

转:http://blog.csdn.net/wei801004/archive/2009/06/13/4264031.aspx

看我的测试代码,似乎应该是在创建子进程之后创建epoll的fd,否则程序将会有问题,试将代码中两个CreateWorker函数的调用位置分别调用,一个在创建epoll fd之前,一个在之后,在调用在创建之前的代码会出问题,在我的机器上(linux内核2.6.26)表现的症状就是所有进程的epoll_wait函数返回0, 而客户端似乎被阻塞了:

服务器端:

 

view plain copy to clipboard print ?
  1. #include <iostream>  
  2. #include <sys/socket.h>  
  3. #include <sys/epoll.h>  
  4. #include <netinet/in.h>  
  5. #include <arpa/inet.h>  
  6. #include <fcntl.h>  
  7. #include <unistd.h>  
  8. #include <stdio.h>  
  9. #include <errno.h>  
  10. #include <sys/types.h>  
  11. #include <sys/wait.h>  
  12. using namespace std;  
  13. #define MAXLINE 5  
  14. #define OPEN_MAX 100  
  15. #define LISTENQ 20  
  16. #define SERV_PORT 5000  
  17. #define INFTIM 1000  
  18. typedef struct task_t  
  19. {  
  20.     int fd;  
  21.     char buffer[100];  
  22.     int n;  
  23. }task_t;  
  24. int CreateWorker(int nWorker)  
  25. {  
  26.     if (0 < nWorker)  
  27.     {  
  28.         bool bIsChild;  
  29.         pid_t nPid;  
  30.         while (!bIsChild)  
  31.         {  
  32.             if (0 < nWorker)  
  33.             {  
  34.                 nPid = ::fork();  
  35.                 if (nPid > 0)  
  36.                 {  
  37.                     bIsChild = false;  
  38.                     --nWorker;  
  39.                 }  
  40.                 else if (0 == nPid)  
  41.                 {  
  42.                     bIsChild = true;  
  43.                     printf("create worker %d success!/n", ::getpid());  
  44.                 }  
  45.                 else  
  46.                 {  
  47.                     printf("fork error: %s/n", ::strerror(errno));  
  48.                     return -1;  
  49.                 }  
  50.             }  
  51.             else   
  52.             {  
  53.                 int nStatus;  
  54.                 if (-1 == ::wait(&nStatus))  
  55.                 {  
  56.                     ++nWorker;  
  57.                 }  
  58.             }  
  59.         }  
  60.     }  
  61.     return 0;  
  62. }  
  63. void setnonblocking(int sock)  
  64. {  
  65.     int opts;  
  66.     opts=fcntl(sock,F_GETFL);  
  67.     if(opts<0)  
  68.     {  
  69.         perror("fcntl(sock,GETFL)");  
  70.         exit(1);  
  71.     }  
  72.     opts = opts|O_NONBLOCK;  
  73.     if(fcntl(sock,F_SETFL,opts)<0)  
  74.     {  
  75.         perror("fcntl(sock,SETFL,opts)");  
  76.         exit(1);  
  77.     }     
  78. }  
  79. int main()  
  80. {  
  81.     int i, maxi, listenfd, connfd, sockfd,epfd,nfds;  
  82.     ssize_t n;  
  83.     char line[MAXLINE];  
  84.     socklen_t clilen;  
  85.     struct epoll_event ev,events[20];  
  86.     struct sockaddr_in clientaddr;  
  87.     struct sockaddr_in serveraddr;  
  88.     listenfd = socket(AF_INET, SOCK_STREAM, 0);  
  89.        bzero(&serveraddr, sizeof(serveraddr));  
  90.     serveraddr.sin_family = AF_INET;  
  91.     char *local_addr="127.0.0.1";  
  92.     inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);  
  93.     serveraddr.sin_port=htons(SERV_PORT);  
  94.       // 地址重用  
  95.     int nOptVal = 1;  
  96.     socklen_t nOptLen = sizeof(int);  
  97.     if (-1 == ::setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &nOptVal, nOptLen))  
  98.     {  
  99.         return -1;  
  100.     }      
  101.     setnonblocking(listenfd);  
  102.     bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));  
  103.     listen(listenfd, LISTENQ);      
  104.       
  105.     CreateWorker(5);  
  106.       
  107.     //把socket设置为非阻塞方式  
  108.       
  109.     //生成用于处理accept的epoll专用的文件描述符  
  110.     epfd=epoll_create(256);      
  111.     //设置与要处理的事件相关的文件描述符  
  112.     ev.data.fd=listenfd;  
  113.     //设置要处理的事件类型  
  114.     ev.events=EPOLLIN|EPOLLET;  
  115.     //ev.events=EPOLLIN;  
  116.     //注册epoll事件  
  117.     epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);  
  118.    
  119.      //CreateWorker(5);  
  120.        
  121.     maxi = 0;  
  122.       
  123.     task_t task;   
  124.     task_t *ptask;  
  125.     while(true)   
  126.     {  
  127.         //等待epoll事件的发生  
  128.         nfds=epoll_wait(epfd,events,20,500);  
  129.         //处理所发生的所有事件       
  130.         for(i=0;i<nfds;++i)  
  131.         {  
  132.             if(events[i].data.fd==listenfd)  
  133.             {                  
  134.                 connfd = accept(listenfd,NULL, NULL);  
  135.                 if(connfd<0){                      
  136.                     printf("connfd<0, listenfd = %d/n", listenfd);  
  137.                     printf("error = %s/n", strerror(errno));  
  138.                     exit(1);  
  139.                 }  
  140.                 setnonblocking(connfd);  
  141.                  
  142.                 //设置用于读操作的文件描述符  
  143.                 memset(&task, 0, sizeof(task));  
  144.                 task.fd = connfd;  
  145.                 ev.data.ptr = &task;  
  146.                 //设置用于注册的读操作事件  
  147.                 ev.events=EPOLLIN|EPOLLET;  
  148.                 //ev.events=EPOLLIN;  
  149.                 //注册ev  
  150.                 epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);  
  151.             }  
  152.             else if(events[i].events&EPOLLIN)  
  153.             {  
  154.                 cout << "EPOLLIN" << endl;  
  155.                 ptask = (task_t*)events[i].data.ptr;  
  156.                 sockfd = ptask->fd;  
  157.                   
  158.                 if ( (ptask->n = read(sockfd, ptask->buffer, 100)) < 0) {  
  159.                     if (errno == ECONNRESET) {  
  160.                         close(sockfd);  
  161.                         events[i].data.ptr = NULL;  
  162.                     } else  
  163.                         std::cout<<"readline error"<<std::endl;  
  164.                 } else if (ptask->n == 0) {  
  165.                     close(sockfd);  
  166.                     events[i].data.ptr = NULL;  
  167.                 }  
  168.                 ptask->buffer[ptask->n] = '/0';  
  169.                 cout << "read " << ptask->buffer << endl;  
  170.                   
  171.                 //设置用于写操作的文件描述符                                  
  172.                 ev.data.ptr = ptask;  
  173.                 //设置用于注测的写操作事件  
  174.                 ev.events=EPOLLOUT|EPOLLET;  
  175.                                   
  176.                 //修改sockfd上要处理的事件为EPOLLOUT  
  177.                 epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);  
  178.             }  
  179.             else if(events[i].events&EPOLLOUT)  
  180.             {     
  181.                 cout << "EPOLLOUT" << endl;  
  182.                 ptask = (task_t*)events[i].data.ptr;  
  183.                 sockfd = ptask->fd;  
  184.                   
  185.                 write(sockfd, ptask->buffer, ptask->n);  
  186.                   
  187.                 //设置用于读操作的文件描述符                
  188.                 ev.data.ptr = ptask;  
  189.                   
  190.                 //修改sockfd上要处理的事件为EPOLIN  
  191.                 epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);  
  192.                 cout << "write " << ptask->buffer;  
  193.                 memset(ptask, 0, sizeof(*ptask));  
  194.                 close(sockfd);  
  195.             }  
  196.         }  
  197.     }  
  198.     return 0;  
  199. }  

 

测试客户端:

 

view plain copy to clipboard print ?
  1. #!/usr/bin/perl  
  2. use strict;  
  3. use Socket;  
  4. use IO::Handle;  
  5. sub echoclient  
  6. {  
  7.     my $host = "127.0.0.1";  
  8.     my $port = 5000;  
  9.     my $protocol = getprotobyname("TCP");  
  10.     $host = inet_aton($host);  
  11.     socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or die "socket() failed: $!";  
  12.     my $dest_addr = sockaddr_in($port, $host);  
  13.     connect(SOCK, $dest_addr) or die "connect() failed: $!";  
  14.     SOCK->autoflush(1);  
  15.     my $msg_out = "hello world/n";  
  16.     print "out = ", $msg_out;  
  17.     print SOCK $msg_out;  
  18.     my $msg_in = <SOCK>;  
  19.     print "in = ", $msg_in;  
  20.     close SOCK;  
  21. }  
  22. #&echoclient;  
  23. #exit(0);  
  24. for (my $i = 0; $i < 9999; $i++)  
  25. {  
  26.     echoclient;  
  27. }  

 lighttpd 也是在创建完子进程后创建的epoll的fd.


http://www.niftyadmin.cn/n/923420.html

相关文章

c语言共用体对齐

还从网上找到共用体内存分配原则的文章&#xff0c;下面列几个例子说明&#xff1a; 1.Union data1{ double d; int i; char c1; char c2[9]; }; sizeof(union data1)的值为16.在编译器默认设置的情况下&#xff0c;该共用体最大基本类型为double,它占8字节&#…

gdb调试正在运行的进程

转&#xff1a;http://hi.baidu.com/brady_home/blog/item/6b92aa8ffdfee2e6f01f369b.html 有时会遇到一种很特殊的调试需求&#xff0c;对当前正在运行的其它进程进行调试&#xff08;正是我今天遇到的情形&#xff09;。这种情况有可能发生在那些无法直接在调试器中运行的进…

find和xargs命令

http://bbs.chinaunix.net/thread-1387521-1-1.html 想好好学习的同学&#xff0c;请认真看完&#xff0c;有点长。 能很好的用好find将是Linux工作的一大幸事&#xff0c;不要奢望一口气记住本文所有的方法&#xff0c;要慢慢的去尝试和领会这…

c语言运算符优先级列表

优先级 运算符 名称或含义 使用形式 结合方向 说明 1 [] 数组下标 数组名[常量表达式] 左到右 () 圆括号 &#xff08;表达式&#xff09;/函数名(形参表) . 成员选择&#xff08;对象&#xff09; 对象.成员名 -> 成员选择&#xff08;指针&#xff0…

gcc如何生成库链接参数

1.gcc包含的c/c编译器 gcc,cc,c,g,gcc和cc是一样的&#xff0c;c和g是一样的。一般c程序就用gcc编译&#xff0c;c程序就用g编译。 2.gcc的基本用法 gcc test.c这样将编译出一个名为a.out的程序gcc test.c -o test这样将编译出一个名为test的程序&#xff0c;-o参数用来指定生成…

linux解压缩tar命令

转&#xff1a;http://blog.csdn.net/teamlet/archive/2008/02/18/2104262.aspx 本文引用了两部分tar的说明&#xff0c;第一部分是举例说明使用tar。第二部分是详细的参数说明。 第一部分&#xff1a; tar命令 tar [-cxtzjvfpPN] 文件与目录 .... 参数&#xff1a; -c …

从一道面试题谈linux下fork的运行机制

转自&#xff1a;http://hi.baidu.com/yuesoq520/blog/item/96fba8eb0632a234b90e2d48.html 今天一位朋友去一个不错的外企面试linux开发职位&#xff0c;面试官出了一个如下的题目&#xff1a; 给出如下C程序&#xff0c;在linux下使用gcc编译&#xff1a; 1 #include "…

perl修改原文件内容

http://www.cnblogs.com/morebetter/archive/2007/05/10/741752.html 很多时候&#xff0c;我们希望对原有文件的内容进行一定的修改&#xff0c;linux虽然有sed这个强大的文本编辑命令&#xff0c;但是他只能生成新文件或打印到screen上(或许sed也具有修改原文件的功能&#x…