服务器同时监听多个客户请求是通过 select
系统调用实现的;
1.1 服务器编程框架
请求队列是各单元之间通信方式的抽象;
1.2 IO 模型
(1)阻塞 IO:阻塞的文件描述符
非阻塞 IO:非阻塞的文件描述符
(2)针对阻塞 IO 执行的系统调用可能因无法立即完成而被操作系统挂起,可能被阻塞的包括 accept、send、recv、connect
;
(3)针对非阻塞 IO 执行的系统调用总是立即返回,即使事件没有发生;如果事件没有立即发送,返回 -1,此时需要根据 errno 来区分是出错还是事件未发生;
对accept、send、recv
而言,事件未发生时 errno 通常被设置为 EAGAIN 或 EWOULDBLOCK;对 connect
,被设置为 EINPROGRESS;
要和其他 IO 通知机制一起使用,比如 IO 复用或 SIGIO 信号;
(4)异步IO:总是立即返回,真正的读写操作由内核完成,向应用程序通知的是 IO 完成事件;
同步 IO:用户代码自行执行 IO 操作,向应用程序通知的是 IO 就绪事件,之后应用调用 IO 读写;
1.3 事件处理模式
同步 IO 模型常用于实现 Reactor,异步 IO 模型用于实现 Proactor
1.3.1 Reactor
主线程负责插入就绪事件到请求队列中;
工作线程从请求队列中取出事件后,根据事件类型决定如何处理;
1.3.2 Proactor
将所有 IO 操作交给主线程和内核来处理,工作线程仅仅负责业务逻辑;
socket 上的读写事件是通过 aio_read / aio_write 向内核注册的,内核通过信号向应用程序报告 IO 完成事件;
1.3.3 模拟Proactor
主线程执行数据的读写操作;
1.4 并发模式
IO 处理单元和多个逻辑单元之间协调完成任务的方法;
1.4.1 半同步/半异步模式
(1)这里的同步是指程序完全按照代码序列顺序执行;
异步指程序的执行需要由系统事件驱动,如中断、信号等;
(2)同步线程用于处理客户逻辑,异步线程用于处理 IO 事件;
1.4.2 领导者/追随者模式
1.5 有限状态机
1.5.1 字符串处理函数
char* strpbrk(char *str1, char *str2)
判断 str1 中的字符是否在 str2 中出现,若出现,返回指针指向 str1 中第一个满足条件的位置,否则,返回 NULL;
*p++ --> (*p)++
// 用来比较参数s1 和s2 字符串,比较时会自动忽略大小写
// 返回值:若参数 s1 和 s2 字符串相同则返回0。
// s1 大于s2 长度则返回大于0 的值,s1 若小于s2 长度则返回小于 0 的值。
// 返回的绝对值为第一个不相等字符之间的差值(ASCII码之间的差值)
int strcasecmp (const char *s1, const char *s2);
// 返回 str1 中第一个不在字符串 str2 中出现的字符下标
size_t strspn(const char *str1, const char *str2);