Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记

文章目录

  • Linux高性能服务器编程(第二篇 深入解析高性能服务器编程)
    • 第9章 I/O复用
      • 1. select
      • 2. poll系统调用
      • 3. epoll系列系统调用
      • 4. 三组I/O复用函数的比较
      • 5-7. I/O复用的高级应用
    • 第10章 信号
      • 1. Linux信号概述
      • 2. 信号函数
      • 3. 信号集
      • 4. 统一事件源
      • 5. 网络编程相关信号
    • 第11章 定时器
      • 1. socket选项SO_RCVTIMEO和SO_SNDTIMEO
      • 2. SIGALRM信号
      • 3. I/O复用系统调用的超时参数
      • 4. 高性能定时器
    • 第12章 高性能I/O框架Libevent
      • 1. I/O框架库概述
      • 2. Libevent源码分析

Linux高性能服务器编程(第二篇 深入解析高性能服务器编程)


第9章 I/O复用

  • I/O复用:程序同时监听多个文件描述符,包括多个socket、多个端口,同时处理用户输入和网络连接、同时处理TCP和UDP等。linux实现I/O复用的系统调用主要有select、poll和epoll

1. select

  • select:在一段指定时间内,监听用户感兴趣的文件描述符上的可读、可写和异常等事件。
#include
// nfds:被监听文件描述符总数,通常设为所有文件描述符最大值加一,文件描述符是从0开始计数的。
// readfds、writefds、exceptfds:可读、可写、异常对应的文件描述符集合,
// select返回时修改通过它们通知应用程序哪些文件描述符已经就绪
// fd_set是包含一个整型数组的结构体,每个元素的每个位标记一个文件描述符,因此可以同时处理的文件描述符的数量有限。
// timeout的成员都为0时立即返回,传入NULL时阻塞到某个文件描述符就绪
// 返回值是就绪文件描述符的总数
int select(int nfds, fd_set* readfds,fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

2. poll系统调用

  • poll:与select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。
#include 
// fds是一个pollfd结构体数组,提供了更多事件
int poll(struct pollfd* fds,nfds_t nfds, int timeout);

3. epoll系列系统调用

  • epoll是Linux特有的I/O复用函数,使用一组函数完成任务;epoll把用户关心的文件描述符上的事件放在内核里的一个事件表里,无需像select和poll那样每次调用都重新传入文件描述符集或者事件集;但是需要一个额外的文件描述符唯一标识内核中的这个事件表。
  • 检索效率是 O ( 1 ) O(1) O(1),不用像select和poll那样遍历所有文件描述符( O ( n ) O(n) O(n)
  • LT模式和ET模式:LT(电平触发 Level Trigger),ET(边缘触发Edge Trigger)
    • LT:默认工作模式,相当于高效的poll,应用程序可以不立即处理事件,下次调用 epoll_wait()还会接收到该事件,直到处理完
    • ET:不管应用程序是否处理都只返回一次该事件,很大程度上降低了同一个epoll事件被重复触发的次数,因此效率比LT高。每个ET状态的文件描述符都应该是非阻塞的,否则读写操作会因为没有后续时间一直处于阻塞状态(饥渴状态)。
  • EPOLLONESHOT事件:多线程或多进程环境下,一个线程或进程读完socket上的数据后开始处理这些数据,又有新数据可读,会触发新事件,由其它线程或进程处理该socket的新事件。我们希望一个socket在任意时刻只被一个线程或进程处理,可以利用EPOLLONESHOT事件实现,操作系统最多触发文件描述符上的一个事件,直到处理该文件描述符的线程或进程重置EPOLLONESHOT事件。
#include 
// size不起作用,只提示内核事件表需要多大
// 返回一个文件描述符
int epoll_create(int size);
// op: 操作类型:EPOLL_CTL_ADD,EPOLL_CTL_MOD,EPOLL_CTL_DEL
// fd: 被操作的文件描述符
// event: 指定事件和用户数据,支持的事件基本与poll相同,多了EPOLLET和EPOLLONESHOT
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
// 一段时间内等待一组文件描述符上的事件,成功时返回就绪的文件描述符的个数
// maxevents指定最多监听多少事件,必须大于0
// epoll_wait如果检测到事件,就将所有就绪事件从内核事件表中复制到第二个参数events指向的数组中,该数组仅用于输出。
int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);

4. 三组I/O复用函数的比较

Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记_第1张图片

5-7. I/O复用的高级应用

  • 非阻塞connect
  • 聊天室程序
  • 同时处理TCP和UDP数据

第10章 信号

  • 信号是由用户、系统或者进程发送给目标进程的信息,以通知目标进程某个状态的改变或系统异常。

1. Linux信号概述

#include
#include
// 把sig发送给目标进程
int kill(pid_t pid,int sig);
// 信号处理函数只有一个参数,指示信号类型
// 信号函数必须是可重入的,避免一些竞态条件,严禁调用不安全函数
typedef void (*__sighandler_t) (int);

#include//Linux可用信号都定义在此
#def SIG_DFL ((__sighandler_t) 0) // 使用信号默认处理方式
#def SIG_IGN ((__sighandler_t) 1) // 忽略目标信号

Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记_第2张图片

2. 信号函数

#include
// 为信号设置处理函数,返回之前的信号处理函数
_sighandler_t signal( int sig,_sighandler_t _handler);
// 更健壮地设置信号处理函数
int sigaction(int sig, const struct sigaction* act,struct sigaction* oact);

3. 信号集

  • 信号集函数
  • 进程信号掩码
  • 被挂起的信号

4. 统一事件源

  • 信号是一种异步事件:信号处理函数和程序主循环是两条不同的执行路线。信号处理函数要尽快执行完毕,避免信号被屏蔽太久,因此把信号的主要处理逻辑放到主循环中,信号处理函数通过管道将信号传递给主循环,主循环再用I/O复用函数监听管道上的信号值。此时信号事件和I/O事件一样被处理,称为统一事件源。

5. 网络编程相关信号

  • SIGHUP:控制终端挂起,对于没有控制终端的网络后台程序,通常利用SIGHUP强制服务器重新读取配置文件。
  • SIGPIPE:向一个读关闭的管道或者socket连接中写数据将引发SIGPIPE信号。
  • SIGURG:带外数据到达。

第11章 定时器

Linux提供的三种定时方法:

  • socket 选项SO_RCVTIMEO和SO_SNDTIMEO
  • SIGALRM信号
  • I/O复用系统调用的超时参数

1. socket选项SO_RCVTIMEO和SO_SNDTIMEO

Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记_第3张图片

2. SIGALRM信号

  • 基于升序链表的定时器
  • 处理非活动连接
  • 利用alarm函数触发SIGALRM信号

3. I/O复用系统调用的超时参数

4. 高性能定时器

  • 时间轮
    Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记_第4张图片
  • 时间堆:最小堆,将超时时间最小的定时器的超时值作为心搏间隔。

第12章 高性能I/O框架Libevent

  • Linux服务器程序必须处理的三类事件:I/O事件,信号事件,定时事件
  • 需考虑三个问题:统一事件源,可移植性,并发编程支持

1. I/O框架库概述

2. Libevent源码分析

你可能感兴趣的:(Linux高性能服务器编程(第二篇 第9-12章)——阅读笔记)