C++面经总结

  • epoll select/pool

    epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是多路复用IO接口select/poll的增强版本。

    特点:获取事件时,无须遍历整个被侦听的描述符集,只需遍历被内核IO事件异步唤醒而加入Ready队列的描述符集合。同时支持水平出发(LT)与边沿出发(ET);

    优点:1. 能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率; 2. 所支持的FD上限是最大可以打开文件的数目(与系统内存有关); 3. IO效率不随FD数目增加而线性下降。传统的select/poll每次调用都会线性扫描全部的集合,导致效率呈线性下降,而epoll是根据每个fd上面的callback函数实现。

    系统调用:

    epoll_create, epoll_ctl和epoll_wait(epoll_pwait)

    • 包含头文件#include<sys/epoll.h>
    • 创建一个epoll句柄

      int epfd = epoll_create(POOL_SIZE);

    • 设置事件监听

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

      示例代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

    int epfd = epoll_create(POLL_SIZE);

    struct epoll_event ev;

    struct epoll_event *events = NULL;

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

    {

        for (n = 0; n < nfds; ++n) {

            if (events[n].data.fd == listener) {

                //如果是主socket的事件的话,则表示

                //有新连接进入了,进行新连接的处理。

                client = accept(listener, (structsockaddr *)&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(epfd, EPOLL_CTL_ADD, client, &ev) < 0) {

                    //设置好event之后,将这个新的event通过epoll_ctl加入到epoll的监听队列里面,

                    //这里用EPOLL_CTL_ADD来加一个新的epoll事件,通过EPOLL_CTL_DEL来减少一个

                    //epoll事件,通过EPOLL_CTL_MOD来改变一个事件的监听方式。

                    fprintf(stderr, "epollsetinsertionerror:fd=%d", client);

                    return -1;

                }

            }

            else if(event[n].events & EPOLLIN)

            {

                //如果是已经连接的用户,并且收到数据,

                //那么进行读入

                int sockfd_r;

                if ((sockfd_r = event[n].data.fd) < 0)

                    continue;

                read(sockfd_r, buffer, MAXSIZE);

                //修改sockfd_r上要处理的事件为EPOLLOUT

                ev.data.fd = sockfd_r;

                ev.events = EPOLLOUT | EPOLLET;

                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd_r, &ev)

            }

            else if(event[n].events & EPOLLOUT)

            {

                //如果有数据发送

                int sockfd_w = events[n].data.fd;

                write(sockfd_w, buffer, sizeof(buffer));

                //修改sockfd_w上要处理的事件为EPOLLIN

                ev.data.fd = sockfd_w;

                ev.events = EPOLLIN | EPOLLET;

                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd_w, &ev)

            }

            do_use_fd(events[n].data.fd);

        }

    }

   

   

   

posted on 2020-08-17 14:45  旭、  阅读(134)  评论(0)    收藏  举报

导航