免费注册 查看新帖 |

Chinaunix

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

问一些关于epoll的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-10-16 20:19 |只看该作者 |倒序浏览
这里看到的[url]http://www.cppblog.com/converse/archive/2008/04/29/48482.html[/url]
自己实验了下
#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 <errno.h>

using namespace std;

#define MAXLINE 5
#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);
    }   
}

int main()
{
    int i, maxi, listenfd, connfd, sockfd,epfd,nfds;
    ssize_t n;
    char line[MAXLINE];
    socklen_t clilen;
    //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
    struct epoll_event ev,events[20];
    //生成用于处理accept的epoll专用的文件描述符
    epfd=epoll_create(256);
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    //把socket设置为非阻塞方式
    //setnonblocking(listenfd);
    //设置与要处理的事件相关的文件描述符
    ev.data.fd=listenfd;
    //设置要处理的事件类型
    ev.events=EPOLLIN|EPOLLET;
    //ev.events=EPOLLIN;
    //注册epoll事件
    epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    char *local_addr="127.0.0.1";
    inet_aton(local_addr,&(serveraddr.sin_addr));//htons(SERV_PORT);
    serveraddr.sin_port=htons(SERV_PORT);
    bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(listenfd, LISTENQ);
    maxi = 0;
    for ( ; ; ) {
        //等待epoll事件的发生
        nfds=epoll_wait(epfd,events,20,500);
        //处理所发生的所有事件     
        for(i=0;i<nfds;++i)
        {
            if(events[i].data.fd==listenfd)
            {
                connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
                if(connfd<0){
                    perror("connfd<0");
                    exit(1);
                }
                //setnonblocking(connfd);
                char *str = inet_ntoa(clientaddr.sin_addr);
                cout << "accapt a connection from " << str << endl;
                //设置用于读操作的文件描述符
                ev.data.fd=connfd;
                //设置用于注测的读操作事件
                ev.events=EPOLLIN|EPOLLET;
                //ev.events=EPOLLIN;
                //注册ev
                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
            }
            else if(events[i].events&EPOLLIN)
            {
                cout << "EPOLLIN" << endl;
                if ( (sockfd = events[i].data.fd) < 0)
                    continue;
                if ( (n = read(sockfd, line, MAXLINE)) < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        events[i].data.fd = -1;
                    } else
                        std::cout<<"readline error"<<std::endl;
                } else if (n == 0) {
                    close(sockfd);
                    events[i].data.fd = -1;
                }
                line[n] = '\0';
                cout << "read " << line << endl;
                //设置用于写操作的文件描述符
                ev.data.fd=sockfd;
                //设置用于注测的写操作事件
                ev.events=EPOLLOUT|EPOLLET;
                //修改sockfd上要处理的事件为EPOLLOUT
                //epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
            }
            else if(events[i].events&EPOLLOUT)
            {   
                sockfd = events[i].data.fd;
                write(sockfd, line, n);
                //设置用于读操作的文件描述符
                ev.data.fd=sockfd;
                //设置用于注测的读操作事件
                ev.events=EPOLLIN|EPOLLET;
                //修改sockfd上要处理的事件为EPOLIN
                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
            }
        }
    }
    return 0;
}


1.在ET模式下,如果发送10个字节,只能接收到5个字节,可是ET的解释是如果状态有变化就会触发epoll_wait就去读,但是发送端发完10个字节,然后close(fd)以后,close动作算状态变化吗
2.在ET模式下,为什么接收完了以后就设置为ev.events=EPOLLOUT|EPOLLET;   而不添加EPOLLIN事件,同样在发送完以后,不添加
EPOLLOUT事件
3.在ET模式下为什么不处理EAGAIN信号,在 man epoll里提到的(an Edge Triggered  usage  requires  more
       clarifiction to avoid stalls in the application event loop. In this example,
       listener is a non-blocking socket on which listen(2) has  been  called.  The
       function  do_use_fd()  uses  the  new  ready file descriptor until EAGAIN is
       returned by either read(2) or  write(2).   An  event  driven  state  machine
       application  should,  after having received EAGAIN, record its current state
       so that at the next call to do_use_fd()  it  will  continue  to  read(2)  or
       write(2) from where it stopped before.)
4.我印象中好像一般都是发送方发完以后close(fd),接收方不close(fd),但是这里我在if(n==0)注释掉close(fd)以后会出现大量的readline error,不知道为什么
5.在改成LT模式下,当发送完10个字节后,比如“1234567890”,会输出2遍“67890”谁知道原因

[[i] 本帖最后由 yuyongyu 于 2008-10-16 20:36 编辑 [/i]]

论坛徽章:
0
2 [报告]
发表于 2008-10-16 20:29 |只看该作者
1.算
2.跟逻辑有关,与epoll无关.

论坛徽章:
0
3 [报告]
发表于 2008-10-16 20:37 |只看该作者
既然算,为什么余下的5个字节读不进去呢

论坛徽章:
0
4 [报告]
发表于 2008-10-16 20:40 |只看该作者
有数据可读并不代表就一定有10个字节的数据

是不是这样?

论坛徽章:
0
5 [报告]
发表于 2008-10-16 21:59 |只看该作者
网络编程高手来回答下我的问题吧

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
6 [报告]
发表于 2008-10-16 23:01 |只看该作者
1.算
2.跟逻辑有关,与epoll无关.
3.你举的这段代码有问题,没有实现非阻塞
4.你应该epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);
5.加点printf吧

论坛徽章:
0
7 [报告]
发表于 2008-10-17 00:26 |只看该作者
LZ,你的测试客户端代码贴出来给我看看.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP