免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4502 | 回复: 8
打印 上一主题 下一主题

[C] epoll 简单例子 求助 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-08-23 18:47 |只看该作者 |倒序浏览
我现在再用epoll 进行测试 但是总有个问题 比较郁闷 如下:

server 端   
监听的socket 为阻塞模式
epoll 设为 ET 模式

在监听的过程中以下面的模式主
while(1){
     epoll_wait();
     if(events.data.fd==listenfd)
     {
          //处理 新来的socket 连接  
         // 调用 accept  产生新的fd
        // 把新的fd 设为非阻塞
       // 以ET模式加入到epoll中
      } else if(events.events&EPOLLIN){
            //处理读事件     
      }else if(events.events&EPOLLOUT) {
           //处理写事件
      }
}

client  端

建立一个socket 阻塞模式  
调用 connect

不调用任何函数 直接sleep(1000000)


上述 过程执行后 server端 出现一次 连接信号(events.data.fd==listenfd)
出现一次 写请求(events.events&EPOLLOUT)


我的问题是  在客户端 我没有调用 recv  为什么在server 会出现 写请求?


各位大侠 给点指点 。。。。。 有关这方面的资料讨论也行啊 。。。
跪谢。。



下面是详细代码 server

#include <iostream>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

using namespace std;

#define MAXLINE 100
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5000
#define INFTIM 1000

void setnonblocking(int sock)
{
    int opts;
    opts=fcntl(sock,F_GETFL);
    if(opts<0)
    {
        perror("fcntl(sock,GETFL)";
        exit(1);
    }
    opts = opts|O_NONBLOCK;
    if(fcntl(sock,F_SETFL,opts)<0)
    {
        perror("fcntl(sock,SETFL,opts)";
        exit(1);
    }
}
void sig_quit(int no)
{
   cout<<"donothing"<<endl;
   
   signal(SIGPIPE,sig_quit);
}

main()
{
   int port=5000;
   int epfd;
   int listenfd;
   int nfds;
   int sockfd;
   struct epoll_event ev;
   struct epoll_event events[20];
   epfd=epoll_create(256);

   struct sockaddr_in caddr;
   struct sockaddr_in saddr;

   listenfd=socket(AF_INET,SOCK_STREAM,0);
  
  // setnonblocking(listenfd);

   ev.data.fd=listenfd;
   ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
  
   epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

   bzero(&saddr,sizeof(struct sockaddr_in));

   saddr.sin_family=AF_INET;
   saddr.sin_port=htons(port);
   saddr.sin_addr.s_addr=INADDR_ANY;
  
   bind(listenfd,(sockaddr*)&saddr,sizeof(struct sockaddr_in));

   listen(listenfd,LISTENQ);

    signal(SIGPIPE,sig_quit);
   
   while(1){
      
       nfds=epoll_wait(epfd,events,20,-1);      

       int i;
       int connfd;
       int clen=sizeof(struct sockaddr_in);
      
       for(i=0;i<nfds;i++)
       {
          if(events.data.fd==listenfd)
          {
              cout<<"listenfd is"<<listenfd<<endl;
              connfd=accept(listenfd,(sockaddr*)&caddr,(socklen_t*)&(clen));
              cout<<"other fd is"<<connfd<<endl;
              setnonblocking(connfd);
              ev.data.fd=connfd;
              ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
              epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
              cout<<"flagA"<<endl;  
          }
          else if(events.events&EPOLLIN)
          {
             char line[MAXLINE];
             memset(line,0,MAXLINE);
             sockfd=events.data.fd;
             cout<<"siteB"<<sockfd<<endl;
             //while(1){
             int flagB=recv(sockfd,line,MAXLINE,0);            

             if(flagB==-1){
                 if(errno==EAGAIN){
                     break;
                 }else if(errno==EPIPE) {
                     epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
                     break;
                 }else{
                    cerr<<"other error!!!!"<<endl;
                    break;
                 }
              }else if(flagB>0)
              cout<<line<<endl;
           // }

             ev.data.fd=sockfd;
             ev.events=EPOLLOUT;
            //epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
             cout<<"flagB"<<endl;
          }
          else if(events.events&EPOLLOUT)
          {  
              char* res="this is server1..";
              int sockfd=events.data.fd;
              
              cout<<"siteC"<<sockfd<<endl;
             // while(1){
                      int flagC=send(sockfd,res,strlen(res),0);
                     //cout<<flagC<<endl;              

                      if(flagC==-1){
                        if(errno==EAGAIN){
                           break;
                        }else if(errno==EPIPE){
                         epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
                         break;
                        }else {
                          break;
                        }
                       }   
            
             // }
               ev.data.fd=sockfd;
               ev.events=EPOLLIN;
             // epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
              cout<<"flagC"<<endl;
          }
       }//for
   }//while
}


client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <iostream>

using namespace std;

main()
{
   int sockfd;
   int numbytes;
   char buf[100];

   memset(buf,0,100);

   struct sockaddr_in other_addr;
   sockfd=socket(AF_INET,SOCK_STREAM,0);
   
   other_addr.sin_family=AF_INET;
   other_addr.sin_port=htons(5000);
   inet_aton("127.0.0.1",&other_addr.sin_addr);
   bzero(&(other_addr.sin_zero),;

   connect(sockfd,(struct sockaddr*)&other_addr,sizeof(struct sockaddr));

   //send(sockfd,"hello!socket..",14,0);

   sleep(100000);


   char c=fgetc(stdin);

   close(sockfd);
}

论坛徽章:
0
2 [报告]
发表于 2011-08-23 19:07 |只看该作者
别这样用 ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
去掉EPOLLOUT

关于EPOLLOUT一般可不用. 如果非要用,在读代码完成后使用epoll_ctl修改之( EPOLLIN|EPOLLET -> EPOLLOUT|EPOLLET ).

论坛徽章:
0
3 [报告]
发表于 2011-08-23 19:09 |只看该作者
EPOLLOUT是会一直触发的

论坛徽章:
0
4 [报告]
发表于 2011-08-24 08:34 |只看该作者
字体斜的看起来好难受啊

论坛徽章:
0
5 [报告]
发表于 2011-08-24 08:58 |只看该作者
回复 2# youshuang

恩 多谢 ~~   说得有道理  如果是 web服务器的话 真的没有必要 去监听EPOLLOUT。。
多谢。。

论坛徽章:
0
6 [报告]
发表于 2011-08-24 08:59 |只看该作者
回复 3# 冻惨鸟


    恩 多谢 ~~ 我再试试

论坛徽章:
0
7 [报告]
发表于 2011-08-24 14:42 |只看该作者
使用epoll来管理阻塞式socket是一定会出问题的:
在 if(events.data.fd==listenfd){}中应该对listenfd循环调用accept产生新的连接,直到返回EAGAIN。但阻塞式socket没法做到这一点。
另外,只要TCP的发送缓冲区未满,EPOLLOUT就会一直被触发

论坛徽章:
0
8 [报告]
发表于 2011-08-25 09:20 |只看该作者
回复 7# marxn
恩 我试试 ~~

论坛徽章:
0
9 [报告]
发表于 2011-08-28 22:10 |只看该作者
学习了。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP