Linux网络编程—Day11 高性能服务器程序框架

news2024/11/13 16:20:04

按照服务器程序的一般原理,讲服务器结构为如下三个主要模块:

  • I/O处理单元
  • 逻辑单元
  • 存储单元

服务器模型

第一种:C/S模型

TCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信 过程中所有机器都是对等的。但由于资源(视频、新闻、软件等)都被数据提供者所垄断,所以几乎所有的网络应用程序都很自然地采用了图C/S(客户端/服务器)模型:所有客户端都通过访问服务器来获取所需的资源。

C/S模型的逻辑很简单:服务器启动后,首先创建一个(或多个)监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户连接。服务器稳定运行之后,客户端就可以调用connect函数向服务器发起连接了。由于客户连接请求是随机到达的异步事件,服务器需要使用某种I/O模型来监听这一事件。

C/S模型非常适合资源相对集中的场合,并且它的实现也很简单,但其缺点也很明显:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应

第二种:P2P模型

P2P模型比C/S模型更符合网络通信的实际情况。它摒弃了以服务器为中心的格局,让网络上所有主机重新回归对等的地位。P2P模型如图所示:以实际使用的P2P模型通常带有一个专门的发现服务器。这个发现服务器通常还提供查找服务(甚至还可以提供内容服务),使每个客户都能尽快地找到自己需要的资源。

P2P模型使得每台机器在消耗服务的同时也给别人提供服务,这样资源能够充分、自由地共享。云计算机群可以看作P2P模型的一个典范。但P2P模型的缺点也很明显:当用户之间传输的请求过多时,网络的负载将加重

从编程角度来讲,P2P模型可以看作C/S模型的扩展:每台主机既是客户端,又是服务器。

服务器编程框架

服务器程序虽然种类繁多,但是其基本框架都一样,不同之处在于逻辑处理。服务器的基本框架如下:

  •  I/O处理单元:是服务器管理客户连接的模块。它通常要完成以下工作:等待并接受新的客户连接,接收客户数据,将服务器响应数据返回给客户端。但是,数据的收发不一定在I/O处理单元中执行,也可能在逻辑单元中执行,具体在何处执行取决于事件处理模式。对于一个服务器机群来说,I/O处理单元是一个专门的接入服务器。它实现负载均衡,从所有逻辑服务器中选取负荷最小的一台来为新客户服务。
  • 逻辑单元:通常是一个进程或线程。它分析并处理客户数据,然后将结果传递给I/O处理单元或者直接发送给客户端。对服务器机群而言,一个逻辑单元本身就是一台逻辑服务器。服务器通常拥有多个逻辑单元,以实现对多个客户任务的并行处理。
  • 网络存储单元:可以是数据库、缓存和文件,甚至是一台独立的服务器。但它不是必须的,比如ssh、telnet等登录服务就不需要这个单元。
  • 请求队列:是各单元之间的通信方式的抽象。I/O处理单元接收到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求。同样,多个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理 竞态条件。请求队列通常被实现为池的一部分,我们将在后面讨论池的概念。对于服务器机群而言,请求队列是各台服务器之间预先建立的、 静态的、永久的TCP连接。这种TCP连接能提高服务器之间交换数据的效率,因为它避免了动态建立TCP连接导致的额外的系统开销。

I/O模型

socket在创建的时候默认是阻塞的。我们可以给socket 系统调用的第2个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统 调用的F_SETFL命令,将其设置为非阻塞的。阻塞和非阻塞的概念能应 用于所有文件描述符,而不仅仅是socket。我们称阻塞的文件描述符为 阻塞I/O,称非阻塞的文件描述符为非阻塞I/O。

  • 针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止。
  • 针对非阻塞I/O执行的系统调用则总是立即返回,而不管事件是否已经发生。如果事件没有立即发生,这些系统调用就返回-1,和出错的情况一样。

显然,我们只有在事件已经发生的情况下操作非阻塞I/O(读、写等),才能提高程序的效率。因此,非阻塞I/O通常要和其他I/O通知机制一起使用,比如I/O复用和SIGIO信号。

I/O复用是最常使用的I/O通知机制。它指的是,应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。I/O复用函数本身是阻塞的,它们能提高程序效率的原因在于它们具有同时监听多个I/O事件的能力。 

SIGIO信号也可以用来报告I/O事件,我们可以为一个目标文件描述符指定宿主进程,那么被指定的宿主进程将捕获到SIGIO信号。这样,当目标文件描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们也就可以在该信号处理函数中对目标文件描述符执行非阻塞I/O操作了。

同步I/O向应用程序通知的是I/O就绪事件,而异步I/O向应用程序通知的是I/O完成事件。

两种高效的事件处理模式

随着网络设计模式的兴起,Reactor和Proactor事件处理模式应运而生。同步I/O模型通常用于实现Reactor模式异步I/O模型则用于实现Proactor模式。不过后面我们将看到,如何使用同步I/O方式模拟出Proactor模式。

Reactor模式

它要求主线程(I/O处理单元)只负责监听文件描述上是否有事件发生,有的话就立即将该事件通知工作线程(逻辑单元)。除此之外,主线程不做任何其他实质性的工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。

使用同步I/O模型实现的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模式

与Reactor模式不同,Proactor模式将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。使用异步I/O模型实现的Proactor模式的工作流程是:

  1. 主线程调用aio_read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序
  2. 主线程继续处理其他逻辑
  3. 当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知应用程序数据已经可用
  4. 应用程序预先定义好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序
  5. 主线程继续处理其他逻辑
  6. 当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,以通知应用程序数据已经发送完毕
  7. 应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭socket。

连接socket上的读写事件是通过aio_read/aio_write向内核注册的,因此内核将通过信号来向应用程序报告连接socket上的读写事件。所以,主线程中的epoll_wait调用仅能用来检测监听socket上的连接请求事件,而不能用来检测连接socket上的读写事件(跟Reactor的区别)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564692.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux开发工具vim

Linux开发工具vim 什么是vim三种模式的转换vim的基本命令gg:定位光标到最开始的行Shiftg:定位光标到结尾行nShiftg:定位光标到任意行Shift$:定位光标到当前行结尾Shift^:定位光标到当前行开始w,b:光标按照单词进行行内…

红黑树 C++

企业里永远是技术驱动理论发展 比起理解红黑树的原理,更重要的是理解红黑树的应用场景,因为某些应用场景的需要,红黑树才会应运而生。 红黑树的特点: 插入,删除,查找都是O(logn)的复杂度。 红黑树的应用…

大数据Doris(二十六):Broker Load基本原理和语法介绍

文章目录 Broker Load基本原理和语法介绍 一、基本原理 二、Broker Load语法 Broker Load基本原理和语法介绍 Apache Doris架构中除了有BE和FE进程之外,还可以部署Broker可选进程,主要用于支持Doris读写远端存储上的文件和目录。例如:Apa…

spring boot +Sa-Token优雅的实现项目鉴权!

1. 技术选型 最近在做登录、授权的功能,一开始考虑到的是spring boot spring security,但spring security太重,而我们是轻量级的项目,所以,spring security不适合我们。 而后考虑spring boot shiro,但s…

【老王读SpringMVC-5】Controller method 是如何执行的?

通过前面对 Controller method 参数绑定的分析,我们知道, 被 RequestMapping 标记 handler method 的执行是通过调用 RequestMappingHandlerAdapter#handle()。 RequestMappingHandlerAdapter#handle() 具体的调用过程如下: 参数解析、han…

【Java基础篇】运算符

作者简介: 辭七七,目前大一,正在学习C/C,Java,Python等 作者主页: 七七的个人主页 文章收录专栏:Java.SE,本专栏主要讲解运算符,程序逻辑控制,方法的使用&…

由浅入深Dubbo网络通信深入解析

目录 1 dubbo中数据格式2 消费方发送请求3 提供方接收请求4 提供方返回调用结果5 消费方接收调用结果6 异步转同步7 异步多线程数据一致8 心跳检查 1 dubbo中数据格式 解决socket中数据粘包拆包问题,一般有三种方式 定长协议(数据包长度一致&#xff09…

5GNR——RACH随机接入流程(1):随机接入的原因

1、随机接入触发原因 1- Initial access from RRC_IDLE; 2- RRC Connection Re-establishment procedure; 3- DL or UL data arrival during RRC_CONNECTED when UL synchronisation status is “non-synchronised”; 4- UL data arrival during RRC_CONNECTED when there are …

Java之运算符

+加号的作用 1.表示正数 2.相加运算符 3.进行字符串的拼接 4.自增 Tips: 运算运算符优于 扩展赋值运算符 byte a ; int b ; ab; 右侧为byte,无需强制转换 aab; 右侧为int,需强制转换为byte,赋给左边…

解码区块链:探索去中心化世界的奥秘与潜力

🐟 区块链技术的基本原理🐟 区块链技术的应用场景🐟 区块链技术的挑战与前景 区块链技术作为一项创新性的技术,引领着数字时代的变革。它以其去中心化、透明性和安全性的特点,为各行业带来了无限可能。在本篇博客中&am…

《程序员面试金典(第6版)》面试题 02.05. 链表求和(构建一个新链表)

题目解析 给定两个用链表表示的整数,每个节点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表形式返回结果。 题目传送门:面试题 02.05. 链表求和 示例: 输入&#x…

漏洞管理基础知识

漏洞管理对于端点安全至关重要,是在安全漏洞导致漏洞之前清除安全漏洞的最主动方法之一。 什么是漏洞 漏洞是软件中的错误代码段,会导致软件崩溃或以程序员从未预料到的方式做出响应。黑客可以利用漏洞对计算机系统进行未经授权的访问或对计算机系统执行…

第五十天学习记录:C语言进阶:位段

位段 什么是位段 位段的声明和结构是类似的&#xff0c;有两个不同&#xff1a; 1、位段的成员可以是int,unsigned int或signed int。 2、位段的成员名后边有一个冒号和一个数字。 #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>//位段-二进制位 struct A {int …

用脚本采集ChatGPT免翻免费镜像

新建了一个网站 ChatGPT人工智能中文站 - ChatGPT人工智能中文站 每天给大家更新可用的国内可用chatGPT免费镜像站 昨天发布了一个教程 本地安装 ChatGPT&#xff01;无需API、 免翻墙、完全免费使用纯正OpenAI的全部功能&#xff01; 支持 Windows、 Mac、NAS、Linux系统 …

led钨丝灯项目笔记

基于ESP-12E的LED钨丝灯作品 原理图&#xff1a; PCB&#xff1a; 嘉立创上面有些封装没有&#xff0c;需要自己画 画完这两个&#xff0c;此时它们还没有相关联&#xff0c;需要将它们关联起来 在封装管理器中将它们关联起来 在这里面就可以找到自己画的封装 如&#xff1a;…

MySQL数据库从入门到精通学习第5天(创建数据表,查看,修改表结构,删除表)

创建数据表&#xff0c;查看&#xff0c;修改表结构 创建数据表查看表结构修改表结构删除表 创建数据表 在对MySQL数据表进行操作之前我们需要创建数据库&#xff0c;并使用USE语句选择数据库。 创建数据库使用CREATE TABLE语句&#xff1a; 语法&#xff1a;CREATE [TEMPOR…

机试打卡 -06 异位词分组(哈希表)

最容易想到的是利用 ord( ) 函数&#xff0c;按照字母计数的特征归类&#xff0c;代码如下&#xff1a; class Solution:def groupAnagrams(self, strs: List[str]) -> List[List[str]]:ans_list[]# 哈希表 {word_count:ans_list中的索引}word_count_dictdict()# 遍历strfo…

NR RLC(三) TM and UM mode

欢迎关注同名微信公众号“modem协议笔记”。 实网下VOLTE通话时常会出现通话无声或者断续的情况&#xff0c;通常的做法是通过检查MO/MT UL发送和DL接收&#xff0c;进一步排查问题原因&#xff0c;modem就避免不了要查看RLC的收发情况&#xff0c;而voice配置一般都是RLC UM …

【Linux系统编程(文件编程)】之读、写文件、文件光标移动

文章目录 一、文件写入二、文件读取三、文件光标移动使用 lseek() 计算文件大小 一、文件写入 write() writes up to count bytes from the buffer starting at buf to the file referred to by the file descriptor fd.write() write() 函数&#xff0c;将从buf缓冲区开始&…

开发实例:Spring Boot、MyBatis和Layui打造增删改查项目

目录导航 1. 技术栈介绍1.1 Springboot1.2 MyBatis1.3 Layui 2. 开发环境2.1 前端示例代码2.2 后端示例代码2.3 数据库建表语句 3. 项目截图4. 运行截图4.1 查询界面4.2 新增界面4.3 修改界面4.4 删除界面 5. 小结6. 完整代码下载 通过学习这个实例项目&#xff0c;我们将积累点…