宁静的天空

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  5 随笔 :: 0 文章 :: 3 评论 :: 0 Trackbacks
Epoll为我们带来什么
      
Q:网络服务器的瓶颈在哪?
A:IO效率。

  在大家苦苦的为在线人数的增长而导致的系统资源吃紧上的问题正在发愁的时候,Linux 2.6内核中提供的System Epoll为我们提供了一套完美的解决方案。传统的select以及poll的效率会因为在线人数的线形递增而导致呈二次乃至三次方的下降,这些直接导致了网络服务器可以支持的人数有了个比较明显的限制。

  自从Linux提供了/dev/epoll的设备以及后来2.6内核中对/dev/epoll设备的访问的封装(System Epoll)之后,这种现象得到了大大的缓解,如果说几个月前,大家还对epoll不熟悉,那么现在来说的话,epoll的应用已经得到了大范围的普及。

  那么究竟如何来使用epoll呢?其实非常简单。
  通过在包含一个头文件#include <sys/epoll.h>以及几个简单的API将可以大大的提高你的网络服务器的支持人数。

  首先通过create_epoll(int maxfds)来创建一个epoll的句柄,其中maxfds为你epoll所支持的最大句柄数。这个函数会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作。在用完之后,记得用close()来关闭这个创建出来的epoll句柄。

  之后在你的网络主循环里面,每一帧的调用epoll_wait(int epfd, epoll_event events, int max events, int timeout)来查询所有的网络接口,看哪一个可以读,哪一个可以写了。基本的语法为:

  nfds = epoll_wait(kdpfd, events, maxevents, -1);

  其中kdpfd为用epoll_create创建之后的句柄,events是一个epoll_event*的指针,当epoll_wait这个函数操作成功之后,epoll_events里面将储存所有的读写事件。max_events是当前需要监听的所有socket句柄数。最后一个timeout 是epoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一直等下去,直到有事件范围,为任意正整数的时候表示等这么长的时间,如果一直没有事件,则范围。一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一个线程的话,则可以用0来保证主循环的效率。

epoll_wait范围之后应该是一个循环,遍利所有的事件:

    for(n = 0; n < nfds; ++n) {
        if(events[n].data.fd == listener) { //如果是主socket的事件的话,则表示有新连接进入了,进行新连接的处理。
            client = accept(listener, (struct sockaddr *) &local, &addrlen);
        if(client < 0){
            perror("accept");
            continue;
    }
    setnonblocking(client); // 将新连接置于非阻塞模式
    ev.events = EPOLLIN | EPOLLET; // 并且将新连接也加入EPOLL的监听队列。

  注意,这里的参数EPOLLIN | EPOLLET并没有设置对写socket的监听,如果有写操作的话,这个时候epoll是不会返回事件的,如果要对写操作也监听的话,应该是EPOLLIN | EPOLLOUT | EPOLLET

    ev.data.fd = client;
    if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) {
        // 设置好event之后,将这个新的event通过epoll_ctl加入到epoll的监听队列里面,这里用EPOLL_CTL_ADD来加一个新的 epoll事件,通过EPOLL_CTL_DEL来减少一个epoll事件,通过EPOLL_CTL_MOD来改变一个事件的监听方式。
        fprintf(stderr, "epoll set insertion error: fd=%d0, client);
        return -1;
        }
    }
    else // 如果不是主socket的事件的话,则代表是一个用户socket的事件,则来处理这个用户socket的事情,比如说read(fd,xxx)之类的,或者一些其他的处理。
        do_use_fd(events[n].data.fd);
    }

  对,epoll的操作就这么简单,总共不过4个API:epoll_create, epoll_ctl, epoll_wait和close。
  如果您对epoll的效率还不太了解,请参考我之前关于网络游戏的网络编程等相关的文章。

  世界变了,原来担心的问题,现在已经不是问题了。
posted on 2008-03-10 23:11 heying 阅读(2106) 评论(1)  编辑 收藏 引用 所属分类: 技术文章

评论

# re: linux sys epool(转) 2008-03-10 23:25 heying
我自己进行下评论:
该文章是我从网络上查找到的,最近我一直在考虑一个问题,象那些网络游戏服务器,是怎么能够支持这么多用户数量呢?
这个问题一直困扰着我,后来我想到了几种方案;
1,利用多线程,每一个客户一个线程;
这种解决方案的问题一目了然,一句话,就是支持用户数量有限;你不可能一个系统中同时创建10w线程;这简直是一个恶梦;
2,利用单线程,运用TCP的短连接,就是说发送完毕数据后等待接收,当接收完毕数据后,关闭该连接;
我原来的公司使用该种方案达到多客户端的目的;我感觉这种方案的缺点应该在于每次通讯需要重新创建连接,会导致系统性能低;但是,实际上我重来没有进行过这方面的系统测试,所以,没有一个具体的测试结果可以告诉大家;
3,使用select;该方法在上文中已经提到;
我前段时间看了linux下telnet客户端的实现代码,不知道是不是因为版本的原因,我发现我看的版本中是使用select实现了单进程用户输入,窗口输出,用户数据发送及用户数据网络接收;我认为这种在低客户量的情况下,是比较好的解决方案;毕竟操作简单;(telnet的文字协议,我会在以后详细解释)
今天我看到了这一篇文章,实际上在我的面前又呈现了一个更广阔的空间;让我真实的了解了网络服务器的通信处理;  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理