第八章 高性能服务器编程框架

  这一章主要介绍服务器的三个主要模块: I/O处理单元、逻辑单元、存储单元。另外服务器的模型有:C/S模型和P2P模型。虽然服务器模型比较多,但是其核心框架都一样,只是在于逻辑处理方面。如下图简单的介绍一台服务器或服务器机群模型的基本框架:

  

  1、I/O模型

  I/O处理单元:I/O处理单元是服务器管理客户连接的模块。主要是等待并受理新的客户连接接收客户数据,将服务器响应数据返回给客户端。

逻辑单元:就是一个个进程或者线程。用于处理客户数据,将结果传递给I/O处理单元或者直接发送给客户端。服务器中通常由多个逻辑单元,以实现多个客户端任务的并行处理。

  网络存储单元:网络存储单元用于存储数据库、缓存以及文件。

  请求队列:请求队列是各个单元之间的通信方式的抽象。请求队列通常被实现为池的一部分。请求队列是各台服务器之间预先建立的静态的永久的TCP连接。

  I/O模型 有阻塞I/O模型和 非阻塞I/O模型。因为socket在创建的时候默认是阻塞的,在创建socket的时候讲第二个参数设置为SOCK_NONBLOCK标志,或通过fcntl系统调用 F_SETFL 命令,将其设置为非阻塞的。对于阻塞I/O执行的系统调用会因为无法立即完成而被操作系统挂起,直到等待事情发生为止。比如:1)客户端通过connect向服务器端发起连接,connect将发送同步报文段给服务器然后等待服务器返回确认报文段。2)如果服务器确认报文段没有立即到达客户端,则connect调用将被挂起,直到客户端收到确认报文段唤醒connect调用。在socket的基础API中,可能被阻塞的系统调用包括 accept send  recv  和 connect.

  对于非阻塞I/O总是需要和其他I/O通知机制一起使用,如果不和其他通知机制一起使用还是阻塞的。比如:I/O复用 和 SIGIO 信号等 另行去处理I/O,处理是异步的。 在非阻塞I/O执行系统调用总是立即返回一个(通知事件结果)。不管事件是否已经发生都会返回。所以对于非阻塞I/O就需要根据errno来区分成功还是失败的情况。事件返回的结果类型有(再来一次 EAGAIN) (期望阻塞 EWOULDBLOCK) (在处理中 EINPROGRESS) 。

  I/O复用是最常用的 I/O通知机制。例如:应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。Linux上常用的I/O复用函数有 select  pull  epoll_wait. 它们能提高程序效率的原因在于它们具有同时监听多个I/O事件能力。

  理论上来说,阻塞I/O和 I/O复用 以及信号驱动I/O都是属于同步I/O模型。因为I/O的读写操作都是在I/O事件发生之后由应用程序完成的。而异步I/O的读写都是立即返回的,不论是否阻塞,因为真正的读写操作已经由内核完成了。也就是说:同步I/O模型要求用户代码自行执行I/O操作,将数据从内核缓存区读入用户缓冲区,或将数据从用户缓冲区写入内核缓冲区。而异步I/O机制则有内核来执行I/O操作,数据在内核缓冲区和用户缓冲区之间的移动是由内核在“后台”完成的。

  可以总结 为同步I/O像应用程序通知的是I/O就绪事件、而异步I/O向应用程序通知的是I/O完成事件。

  I/O模型对比

    1)阻塞I/O : 程序阻塞于读写函数;

    2)I/O复用: 程序阻塞于I/O复用系统调用,但可同时监听多个I/O事件。对I/O本身的读写操作是非阻塞的。

    3)SIGIO信号: 信号触发读写就绪事件,用户陈谷执行读写操作。程序没有阻塞阶段。

    4)异步I/O: 内核执行读写操作并触发读写完成事件。程序没有阻塞阶段。  

  

  2、Reactor 和 Proactor 事件处理模式

  事件处理的两种模式:Reactor 和 Proactor  通常服务器程序需要处理三类事件:I/O事件、信号、定时事件。同步I/O模型通常使用 Reactor模式,异步I/O模式用Proactor处理。也可以通过同步I/O模拟出 Proactor模式;

  Reactor模式:她只要求主线程(i/o处理单元)监听文件描述上是否有事件发生,有就立即通知通知工作线程(逻辑单元)处理任务。所有的读写处理数据都在线程上执行。使用同步I/O模型(epoll_wait为例)实现Reactor模式工作流程是:1)主线程往 epoll 内核事件表注册 socket 上的读就绪事件。2)主线程调用 epoll_wait 等待socket 上有数据可读。3)当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入请求队列。4)请求队列上的某一个线程将会被唤醒。它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册socket上的写就绪事件。5)主线程调用 epoll_wait等待socket可写。6)当socket可写时,epoll_wait通知主线程。主线程将socket可写事件放入请求队列。7)请求队列上的某一个线程将会被唤醒。它从socket上写入服务器处理客户请求的结果。这是一个环形的操作,如下图:

  

  Proactor模式:她是将I/O操作都交给主线程和内核处理。工作线程仅负责业务逻辑。使用异步I/O(aio_read和 aio_write为例) 实现Proactor模式。1)主线程调用aio_read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序。2)主线程继续处理其他逻辑。3)当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,已通知应用程序数据已可用。4)应用程序预先定义好信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序。5)主线程继续处理其他逻辑。6)当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,以通知应用程序数据已经发送完毕。7)应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,决定是否关闭socket.如下图:

  

  3、池

  池有很多种,常见的有 内存池、进程池、线程池、连接池。池是在服务器启动时预先初始化创建好的长连接。已达到空间换时间的概念提高效率。当然逾期初始化好的数据对它的大小就难以把控了,当然也可以动态扩容。

     

linux高性能服务器编程 (八) --高性能服务器程序框架的更多相关文章

  1. Linux高性能服务器编程:高性能服务器程序框架

    服务器有三个主要模块: (1)I/O处理单元 (2)逻辑单元 (3)存储单元 1.服务器模型 C/S模型 逻辑:服务器启动后,首先创建一个或多个监听socket,并调用bind函数将其绑定到服务器感兴 ...

  2. Linux之网络编程:时间服务器

    基于TCP-服务器 1,创建一个socket套接字 int socket(int domain,int type,int protocol) domain:IP地址族,AF_INET(IPv4).AF ...

  3. 【linux草鞋应用编程系列】_4_ 应用程序多线程

    一.应用程序多线程     当一个计算机上具有多个CPU核心的时候,每个CPU核心都可以执行代码,此时如果使用单线程,那么这个线程只能在一个 CPU上运行,那么其他的CPU核心就处于空闲状态,浪费了系 ...

  4. Linux C网络编程学习笔记

    Linux C网络编程总结报告 一.Linux C 网络编程知识介绍: 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户端:(client) 在网络程序中, ...

  5. Linux 高性能服务器编程——高性能服务器程序框架

    问题聚焦:     核心章节.     服务器一般分为如下三个主要模块:I/O处理单元(四种I/O模型,两种高效事件处理模块),逻辑单元(两种高效并发模式,有效状态机)和存储单元(不讨论). 服务器模 ...

  6. Linux 高性能服务器编程——Linux服务器程序规范

    问题聚焦:     除了网络通信外,服务器程序通常还必须考虑许多其他细节问题,这些细节问题涉及面逛且零碎,而且基本上是模板式的,所以称之为服务器程序规范.     工欲善其事,必先利其器,这篇主要来探 ...

  7. Linux 高性能服务器编程——IP协议详解

    1 IP服务特点 IP协议是TCP/IP协议族的动力,它为上层协议提供无状态.无连接.不可靠的服务. 无状态:IP通信双方不同步传输数据的状态信息,因此IP数据包的发送.传输和接收都是无序的.     ...

  8. Linux 高性能服务器编程——多线程编程

    问题聚焦:     在简单地介绍线程的基本知识之后,主要讨论三个方面的内容:    1 创建线程和结束线程:    2 读取和设置线程属性:    3 线程同步方式:POSIX信号量,互斥锁和条件变量 ...

  9. Linux 高性能服务器编程——多进程编程

    问题聚焦:     进程是Linux操作系统环境的基础.     本篇讨论以下几个内容,同时也是面试经常被问到的一些问题:     1 复制进程映像的fork系统调用和替换进程映像的exec系列系统调 ...

随机推荐

  1. 浅浅的叙WPF之数据驱动与命令

    之前一直开发Winfrom程序,由于近一段时间转开发Wpf程序,刚好拜读刘铁锰<深入浅出WPF>对此有一些理解,如有误导指出,还望斧正!!! 说道WPF数据驱动的编程思想,MVVM,是为W ...

  2. C#读写调整修改设置UVC摄像头画面-逆光对比

    有时,我们需要在C#代码中对摄像头的逆光对比进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的 ...

  3. Typora使用手册

    块状元素: 标题: # 标题1 ## 标题2 ### 标题3 #### 标题4 ##### 标题5 ###### 标题6 使用快捷键: Ctrl + 1-6 块引用 使用符号 > 就可以进入引用 ...

  4. scp 基本用法(提高scp传输速度)

    Outline spc 可以帮你实现: Linux Server 之间互传数据: Linux Server 和 Windows Server 之间互传数据: 参考: https://www.cnblo ...

  5. Socker编程之TCP

    一:TCP介绍 TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 7 ...

  6. Mysql关键字Explain 性能优化神器

    Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析查询语句或是结构的性能瓶颈.在select语句之前增加explaion关键字,MySQL会在查询上设置一个标记,执行查 ...

  7. ASP.NET Core中返回 json 数据首字母大小写问题

    ASP.NET Core中返回 json 数据首字母大小写问题 在asp.net core中使用ajax请求动态绑定数据时遇到该问题 后台返回数据字段首字母为定义的大写,返回的数据没有问题 但是在前台 ...

  8. C# 判断域名或ip+端口号 是否能正常连接?

    private static ManualResetEvent TimeoutObject = new ManualResetEvent(false); /// <summary> /// ...

  9. Python之路(第四十三篇)线程的生命周期、全局解释器锁

    一.线程的生命周期(新建.就绪.运行.阻塞和死亡) 当线程被创建并启动以后,它既不是一启动就进入执行状态的,也不是一直处于执行状态的,在线程的生命周期中,它要经过新建(new).就绪(Ready).运 ...

  10. 小程序开发 解析内容中unicode转中文编码显示问题

    如果对你有帮助的话麻烦点个[推荐]~最好还可以follow一下我的GitHub~感谢观看! 小程序后台返回数据的时候,html内容是经过unicode编码的不能直接显示,里边全是类似&#xxx ...