Chinaunix首页 | 论坛 | 博客
  • 博客访问: 428075
  • 博文数量: 132
  • 博客积分: 2511
  • 博客等级: 大尉
  • 技术积分: 1385
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-11 15:10
文章分类

全部博文(132)

文章存档

2012年(18)

2011年(35)

2010年(60)

2009年(19)

分类: LINUX

2010-04-07 14:29:50

  昨天看了这篇文章,本来是讨论epoll——fd的创建应该是在多进程被创建之后还是之前的,不过引申出一个问题,就是如果监听套接口是ET时,会不会存在连接不能被及时accept的情况。
  自己写代码试了一下,当监听套接口设为ET时,确实存在不能被及时accept的情况。也就是说,当listen_fd被设备为ET方式并且其上有事件发生时,表明有新连接到来,进程去accept,此时如果TCP的就结果队列里有两个连接,则只有一个连接被accept。。
  发生这个问题的原因是ET在套接字上有事件发生时,只报告一次,而epoll_wait的返回值表明的是有事件发生的套接字的数量,而不是事件数,也就是说,它没有表明该套接字上有几个事件发生。。当我们采用以下方式去处理时,就会发生问题:假如此时epoll只监视listen_fd,则当listen_fd上有事件发生时,epoll_wait返回的n是1,但此时可能有多个连接同时到来,而我们却不知道有几个连接。。在处理中,accept往往会只被调用一次。。

epfd = epoll_create(256);
ev.data.fd = listen_fd;
ev.events = EPOLLIN|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&ev);

for(;;)

{

     n = epoll_wait(epfd,events, 20, 500);

     for(i = 0; i<n; i++)
     {
        //process..

        if(events[i].data.fd == listen_fd)
        {

            //accept the connection..

        }

    }

}



测试代码(服务器端):

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/epoll.h>

int main()
{
    int listen_fd,accept_fd,flag;
    struct sockaddr_in addr,remote_addr;
    int addr_len = sizeof(struct sockaddr_in);
    int i;
    struct epoll_event ev,events[20];
    int epfd;
    int ev_s = 0;

    if ((listen_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("create socket error");
        exit(1);
    }
    if (setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&flag,sizeof(flag)) == -1)
    {
        perror("setsockopt error");
    }

    int flags = fcntl(listen_fd, F_GETFL, 0);
    fcntl(listen_fd, F_SETFL, flags|O_NONBLOCK);

    bzero(&addr, addr_len);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8800);
    addr.sin_addr.s_addr = INADDR_ANY;

    if(bind(listen_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1)
    {
        perror("bind error");
        exit(1);
    }
    if (listen(listen_fd,5) == -1)
    {
        perror("listen error");
        exit(1);
    }

    epfd = epoll_create(256);
    
    ev.data.fd = listen_fd;
    ev.events = EPOLLIN|EPOLLET;
    //ev.events = EPOLLIN;
    epoll_ctl(epfd,EPOLL_CTL_ADD,listen_fd,&ev);

    for(;;)
    {
        ev_s = epoll_wait(epfd,events, 20, 500);
        for(i = 0; i<ev_s; i++)
        {
            printf("epool_wait returns!number:%d\n", ev_s);
            if(events[i].data.fd == listen_fd)
            {
                printf("Porcessing connection...\n");
                accept_fd = accept(listen_fd,
                        (struct sockaddr *)&remote_addr, &addr_len);
                //close(accept_fd);
            }
        }
    }

    return 0;
}


客户端测试代码(取自文章顶部的链接,稍做了修改):

#!/usr/bin/perl

use strict;
use Socket;
use IO::Handle;

sub echoclient
{
    #my $host = "127.0.0.1";

    my $host = "10.24.55.8";
    my $port = 8800;

    my $protocol = getprotobyname("TCP");
    $host = inet_aton($host);

    socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or die "socket() failed: $!";

    my $dest_addr = sockaddr_in($port, $host);
    connect(SOCK, $dest_addr) or die "connect() failed: $!";
}

for (my $i = 0; $i < 9; $i++)
{
    echoclient;
}
#sleep 200;


  测试中,服务器端将listen_fd放入epooll中,有事件时accept新连接,不做处理,依靠打印信息判断LT和ET模式下是否能够处理所有的新建连接;客户端则只发起特定处理的连接。
  测试结果:将listen_fd以ET方式在epoll中监视时,会出现处理的连接比实际发起的连接数少的情况;LT方式下不会出现此情况。


  结论:listen_fd应该以LT方式(epoll默认的方式)被监听。
  问题:上面的perl脚本是直接拿来用的,把最后那个sleep打开时,发现每次执行的时候,只有一个连接是ESTABLISHED的,其它都是CLOSE_WAIT,为啥?
阅读(1162) | 评论(0) | 转发(0) |
0

上一篇:Little Endian和Big Endian

下一篇:curl用法

给主人留下些什么吧!~~