当前位置:首页 > 公众号精选 > C语言与CPP编程
[导读]揭开高性能服务器底层面纱一、前言我们经常听说高性能服务器,那什么是高性能服务器;用大白话来解释就是说处理事件快,效率高,占用服务器资源少,多路复用等等集万千宠爱于一身;但是,往往要想做到高性能,这是非常难的,需要一个好的优秀的架构和底层接口。这篇文章只限于linux平台,对于wi...

揭开高性能服务器底层面纱

一、前言

我们经常听说高性能服务器,那什么是高性能服务器;用大白话来解释就是说处理事件快,效率高,占用服务器资源少,多路复用等等集万千宠爱于一身;但是,往往要想做到高性能,这是非常难的,需要一个好的优秀的架构和底层接口。

这篇文章只限于 linux 平台,对于 windows 平台下,可以去参考下 IOCP 的用法,这里就不多说了~

目前主流的高性能服务器底层都是封装了 EPOLL 接口,使用 epoll 进行事件处理,为什么 epoll 可以作为高性能服务器底层事件处理?那就让我们从源码下手,来揭开面纱~

二、源码解读

两个至关重要的结构体

eventpoll结构体:

/*
 * 此结构体存储在file->private_data中
 */
/*
    eventpoll结构体是epoll的核心里面存放着许多信息,主要包括
    1. struct rb_root rbr;这是一颗红黑树的根节点,代表着一颗红黑树,
    红黑树下面挂的是我们感兴趣的socket的事件,当我们调用epoll_ctl向
    epoll添加感兴趣的socket事件时,系统将我们的传递的信息封装成
    struct epitem结构体,然后挂到这颗红黑树的相应节点上
    2.struct list_head rdllist;这是一个双向链表,这个双向链表中存放
    的是就绪的事件当我们调用epoll_wait的时候这些事件会返回给用户
    3.struct file *file;文件结构指针,指向epoll文件
    */
struct eventpoll {
  // 自旋锁,在kernel内部用自旋锁加锁,就可以同时多线(进)程对此结构体进行操作
  // 主要是保护ready_list
  spinlock_t lock;
  // 这个互斥锁是为了保证在eventloop使用对应的文件描述符的时候,文件描述符不会被移除掉
  struct mutex mtx;
  // epoll_wait使用的等待队列,和进程唤醒有关
  wait_queue_head_t wq;
  // file->poll使用的等待队列,和进程唤醒有关
  wait_queue_head_t poll_wait;
  // 就绪的描述符队列,双向链表
  struct list_head rdllist;
  // 通过红黑树来组织当前epoll关注的文件描述符
  struct rb_root rbr;
  // 在向用户空间传输就绪事件的时候,将同时发生事件的文件描述符链入到这个链表里面
  struct epitem *ovflist;
  // 对应的user
  struct user_struct *user;
  // 对应的文件描述符
  struct file *file;
  // 下面两个是用于环路检测的优化
  int visited;
  struct list_head visited_list_link;
};
epitem结构体

// 对应于一个加入到epoll的文件  
struct epitem {  
    // 挂载到eventpoll 的红黑树节点  
    struct rb_node rbn;  
    // 挂载到eventpoll.rdllist 的节点  
    struct list_head rdllink;  
    // 连接到ovflist 的指针  
    struct epitem *next;  
    /* 文件描述符信息fd   file, 红黑树的key */  
    struct epoll_filefd ffd;  
    /* Number of active wait queue attached to poll operations */  
    int nwait;  
    // 当前文件的等待队列(eppoll_entry)列表  
    // 同一个文件上可能会监视多种事件,  
    // 这些事件可能属于不同的wait_queue中  
    // (取决于对应文件类型的实现),  
    // 所以需要使用链表  
    struct list_head pwqlist;  
    // 当前epitem 的所有者  
    struct eventpoll *ep;  
    /* List header used to link this item to the "struct file" items list */  
    struct list_head fllink;  
    /* epoll_ctl 传入的用户数据 */  
    struct epoll_event event;  
};
int epoll_create(int size);

作用:调用epoll_create方法创建一个epoll的句柄

源码:

SYSCALL_DEFINE1(epoll_create, int, size)
{
  if (size <= 0)
    return -EINVAL;

  return do_epoll_create(0);
}
从源码来看,其实 size 这个参数并没有什么作用,只要大于 0 就可以了~

我从其他地方获取资料说的是:以前底层实现是哈希表,现在是红黑树,为了兼容所以才保留了这个参数,也不知道真假,权当了解一下~

接着看下do_epoll_create

static int do_epoll_create(int flags)
{
  int error, fd;
  struct eventpoll *ep = NULL;
  struct file *file;

  /* Check the EPOLL_* constant for consistency.  */
  BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC);

  if (flags 
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭
关闭