【Linux高性能服务器编程】——高性能服务器框架

 16b9d0dfc990426e968798e2f5a7628b.png

hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之高性能服务器框架介绍,在这篇文章中,你将会学习到高效的创建自己的高性能服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!!

希望这篇文章能对你有所帮助9fe07955741149f3aabeb4f503cab15a.png,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!1a2b6b564fe64bee9090c1ca15a449e3.png注:这章对于高性能服务器的架构非常重要哟!!!

03d6d5d7168e4ccb946ff0532d6eb8b9.gif         

目录

 一.服务器模型

    1.1 C/S模型

C/S模型的组成

C/S模型的通信过程

1.2 P2P模型

Linux 中的服务器 P2P 模型

二. 两种高效的服务器事件处理

2.1 Reactor模式

Linux 中的 Reactor 模式

2.2. Proactor模式

Linux 中的 Proactor 模式

 一.服务器模型

    1.1 C/S模型

C/S模型,即客户端/服务器模型(Client/Server Model),是一种网络计算模型,它将任务和工作负载分配到客户端和服务器两个不同的计算环境中。在这种模型中,客户端负责发送请求,而服务器负责处理请求并返回响应。

如图: 

C/S模型的组成

  1. 客户端(Client)

    • 客户端通常是用户直接交互的应用程序,例如网页浏览器、电子邮件客户端或移动应用。
    • 它向服务器发送请求,并接收服务器返回的数据。
    • 客户端可以执行一些计算任务,但主要依赖于服务器来处理复杂或数据密集型的任务。
  2. 服务器(Server)

    • 服务器是一个提供数据存储和服务的系统,它响应客户端的请求。
    • 服务器通常拥有强大的计算能力和存储空间,能够处理多个客户端的请求。
    • 服务器可以运行数据库管理系统,如 MySQL 或 PostgreSQL,以及各种服务器软件,如 HTTP 服务器 Apache 或 Nginx。

C/S模型的通信过程

  1. 请求:客户端建立一个到服务器的连接,并发送一个请求。
  2. 处理:服务器接收到请求后,对其进行处理。
  3. 响应:服务器将处理结果作为响应发送回客户端。
  4. 关闭连接:客户端接收响应后,通常关闭与服务器的连接

我们可以使用多线程来进行实现,一个连接的业务处理分配一个线程:

 

核心代码如下:

线程处理函数:

// 定义线程函数
void *handle_client(void *socket_desc) {int sock = *(int*)socket_desc;char *message;int len;// 接收客户端数据while((len = read(sock, message, 1024)) > 0) {printf("收到数据:%s\n", message);// 发送响应write(sock, "Hello, Client!", 14);memset(message, 0, 1024);}// 关闭套接字close(sock);return 0;
}

 主函数:

​
int main() {int sock, newsock, clilen;struct sockaddr_in serv_addr, cli_addr;int *new_sock;pthread_t thread_id;// 创建套接字sock = socket(AF_INET, SOCK_STREAM, 0);if (sock == -1) {printf("Could not create socket");}// 填充服务器地址结构serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = INADDR_ANY;serv_addr.sin_port = htons(8080);// 绑定套接字到地址if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("bind failed");return -1;}// 监听套接字listen(sock, 3);printf("Listening...\n");clilen = sizeof(cli_addr);// 接受客户端连接while((newsock = accept(sock, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen)) > 0) {// 创建新线程new_sock = malloc(1);*new_sock = newsock;if (pthread_create(&thread_id, NULL, handle_client, (void*)new_sock) < 0) {perror("could not create thread");return -1;}pthread_detach(thread_id);}// 关闭套接字if (newsock < 0) {perror("accept failed");return -1;}return 0;
}​

 

1.2 P2P模型

在 Linux 环境中,P2P(点对点)模型是一种直接连接两个或多个计算机的网络通信方式,其中没有中心服务器参与数据传输。在 P2P 模型中,每个节点既是客户端也是服务器,可以相互发送和接收数据。

Linux 中的服务器 P2P 模型

  1. 节点间通信

    • P2P 网络中的每个节点都直接与其他节点通信,没有中央服务器来处理连接和数据传输。
    • 节点之间通过套接字(sockets)进行通信,可以建立全双工连接。
  2. 网络拓扑

    • P2P 网络可以是星型、网状或混合型,取决于节点的连接方式和网络结构。
    • 节点可以通过各种机制发现其他节点,如 DHT(分布式哈希表)算法。

如图:

代码和C/S相似,大家可以去网上自行寻找资料,这里就不再重复了哦!

二. 两种高效的服务器事件处理

2.1 Reactor模式

Reactor 模式是一种事件驱动的网络编程模式,用于处理高并发网络服务。在 Reactor 模式中,一个或多个线程负责监听网络事件,当事件发生时,例如新的连接请求、数据到达等,Reactor 模式会触发相应的处理函数来处理这些事件。

Linux 中的 Reactor 模式

  1. 事件循环

    • Reactor 模式通常包含一个事件循环,该循环不断地轮询所有事件,等待事件发生并处理它们。
  2. 事件处理器

    • 事件处理器是处理特定事件的函数,它们通常与事件类型相关联。
  3. 事件分派器

    • 事件分派器负责将事件分发给相应的事件处理器。
  4. 事件源

    • 事件源是产生事件的实体,例如网络套接字、文件描述符等。

流程图如下:

  

使用的是同步I/O模型。

1) 主线程往epol l 内核事件表中注册socket上的读就绪事件。

2) 主线程调用epol l _ wait等待 socket 上有数据可读。 

3)当socket 上有数据可读时, epoll _ wait通知主线程。主线程则将socket 可读事件放入请求队列。  

4)睡眠在请求队列上的某个工作线程被唤醒,它从 socket 读取数据,并处理客户请求,然后往epol l内核事件表中注册该socket 上的写就绪事件。

5) 主线程调用epoll _ wait等待 socket 可写。

6)当socket 可写时, epoll wait通知主线程。主线程将socket 可写事件放入请求队列。 

7)睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的结果。
 

 

2.2. Proactor模式

Proactor 模式是一种事件驱动的网络编程模式,与 Reactor 模式类似,但它使用异步 I/O 操作来处理网络事件。在 Proactor 模式中,一个或多个线程负责监听网络事件,当事件发生时,例如新的连接请求、数据到达等,Proactor 模式会触发相应的处理函数来处理这些事件。

Linux 中的 Proactor 模式

  1. 事件循环

    • Proactor 模式通常包含一个事件循环,该循环不断地轮询所有事件,等待事件发生并处理它们。
  2. 事件处理器

    • 事件处理器是处理特定事件的函数,它们通常与事件类型相关联。
  3. 事件分派器

    • 事件分派器负责将事件分发给相应的事件处理器。
  4. 事件源

    • 事件源是产生事件的实体,例如网络套接字、文件描述符等。
  5. 异步 I/O 操作

    • Proactor 模式使用异步 I/O 操作来处理网络事件,这样可以减少线程间的上下文切换,提高系统的性能。

 具体流程图如下:

1)主线程调用aio _ read 函数向内核注册socket 上的读完成事件, 并告诉内核用户读缓冲区的位置,以及读操作完成时如何通知应用程序(这里以信号为例,详情请参考sigevent的man手册)。

2)主线程继续处理其他逻辑。 

3)当socket上的数据被读入用户缓冲区后,内核将向应用程序发送一个信号,以通知应用程序数据已经可用。  

4)应用程序预先定义好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用aio _ write函数向内核注册 socket上的写完成事件, 并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序(仍然以信号为例)。

5)主线程继续处理其他逻辑。  

6)当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,以通知应用程序数据已经发送完毕。  

7)应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭 socket。

 这里给出一个代码例子:

事件处理函数:

// 事件处理函数
void *handle_connection(void *socket_desc) {int sock = *(int*)socket_desc;char *message;int len;// 接收客户端数据while((len = read(sock, message, 1024)) > 0) {printf("收到数据:%s\n", message);// 发送响应write(sock, "Hello, Client!", 14);memset(message, 0, 1024);}// 关闭套接字close(sock);return 0;
}

循环逻辑:

 while(1) {activity = epoll_wait(epollfd, events, MAX_EVENTS, -1);if ((activity < 0) && (errno != EINTR)) {printf("epoll_wait error");return -1;}for (i = 0; i < activity; i++) {if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) {// 处理错误情况close(events[i].data.fd);continue;}if (events[i].data.fd == sock) {// 有新的客户端连接newsock = accept(sock, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen);printf("新的客户端连接:%s\n", inet_ntoa(cli_addr.sin_addr));client_sockets[i] = newsock;event.events = EPOLLIN;event.data.fd = newsock;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, newsock, &event) == -1) {perror("epoll_ctl failed");return -1;}} else {// 处理客户端数据new_sock = malloc(1);*new_sock = events[i].data.fd;if (pthread_create(&thread_id, NULL, handle_connection, (void*)new_sock) < 0) {perror("could not create thread");return -1;}pthread_detach(thread_id);}}}// 关闭 epoll 实例close(epollfd);return 0;
}

在这个例子中,服务器端使用 epoll 函数来实现 Proactor 模式,创建一个简单的服务器。服务器使用 pthread 库来创建多线程来处理多个客户端的连接,每个连接都由一个单独的线程处理。服务器收到客户端的请求后,发送一个响应,并关闭与客户端的连接。(不是完整代码哦!)

   好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦4d7d9707063b4d9c90ac2bca034b5705.png!! 感谢大家的阅读,我还会持续创造网络编程相关内容的,记得点点小爱心和关注哟!2cd0d6ee4ef84605933ed7c04d71cfef.jpeg     

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

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

相关文章

Win 进入桌面黑屏,只有鼠标

大家好&#xff0c;我叫秋意零。 今天&#xff0c;遇到一个同事电脑进入桌面黑屏&#xff0c;只有鼠标。经过询问沟通&#xff0c;说是 Windows 突然进行了自动更新&#xff0c;更新之后桌面就黑了屏。经过查询是一个桌面进程没启动才会导致桌面黑屏。首先分两种情况&#xff0…

代码随想录算法训练营DAY30|C++回溯算法Part.6|332.重新安排行程、51.N皇后、31.解数独

文章目录 332.重新安排行程思路死循环的问题记录映射关系解决死循环并解决字母序问题 伪代码实现CPP代码 51.N皇后思路伪代码实现CPP代码 31.解数独伪代码实现CPP代码 332.重新安排行程 力扣题目链接 文章讲解&#xff1a;332.重新安排行程 状态&#xff1a;题目要求所有机票都…

工业级3D可视化工具HOOPS Visualize, 快速构建移动端和PC端工程应用程序!

HOOPS Visualize是一款强大的工业级3D渲染引擎&#xff0c;帮助您打造出众的工程应用程序。HOOPS Visualize的基石是图形内核&#xff0c;这是一种全功能的&#xff0c;以工程为重点的场景图技术&#xff0c;我们称为Core Graphics。Core Graphics集成到一个框架中&#xff0c;…

大模型改变了NLP的游戏规则了吗

NLP已经死了吗&#xff1f; 自从 ChatGPT 横空出世以来&#xff0c;自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09; 研究领域就出现了一种消极的声音&#xff0c;认为大模型技术导致 NLP “死了”。在某乎上就有一条热门问答&#xff0c;大…

Docker 部署网页版 vscode (code-server)

什么是 code-server code-server 是一个基于 Visual Studio Code 的开源项目&#xff0c;它允许你通过 Web 浏览器来使用 Visual Studio Code 的编辑功能。这意味着你可以在任何设备上&#xff0c;只要有浏览器和网络连接&#xff0c;就可以访问和使用 Visual Studio Code&…

漫谈HAMR硬盘的可靠性-2

很显然&#xff0c;HAMR已经成为业内用于提升HDD硬盘容量硬盘的技术手段。三家机械硬盘HDD厂商&#xff0c;希捷、西数、东芝都已对HAMR硬盘进行了十多年的研究&#xff0c;但只有希捷大胆押注HAMR。相反&#xff0c;东芝和西部数据在采用HAMR之前选择了能量辅助垂直磁记录&…

Axure中的样式

样式 首先说一下Axure里面的原点位置 如下图&#xff1a; 还有一个办法是我们选中我们的按钮&#xff0c;如上图&#xff0c;然后打开右边的样式&#xff0c;可以看按钮的x&#xff0c;y属性&#xff0c;类似于游戏中unity软件的x&#xff0c;y属性&#xff0c;类似于html中…

程序设计语言—Python几种语言区别的总结

程序设计语言篇—Python&几种语言区别的总结 文章目录 程序设计语言篇—Python&几种语言区别的总结一、Python介绍&理解1.1 Python基础1.2 Python规范 二、标识符&变量&常量三、数据类型&运算符和表达式3.1 数据类型3.2 运算符&表达式 四、常用的函…

Linux 系统IO函数之stat、lstat函数

1、stat函数 要点&#xff1a; int stat(const char *pathname, struct stat *statbuf); 作用&#xff1a;查看文件的信息 man 2 stat/return value1、stat结构体&#xff1a; 2、sturct stat 结构体中 st_mode 的含义&#xff08;文件的类型和存取的权限&#xff09;: st_mo…

华媒舍:百度竞价排名如何提升点击率

在网络推广中&#xff0c;提升点击率是十分重要的。运用百度搜索引擎广告是一种常用的提升点击率的形式。而百度竞价推广是搜索引擎所提供的一种付费流量方法&#xff0c;根据提高网站在搜索结果中的排名&#xff0c;可以有效提升点击率。下面我们就详细介绍如何运用百度竞价推…

每日OJ题_其它背包问题①_力扣474. 一和零(二维费用01背包)

目录 力扣474. 一和零 解析代码 代码优化 力扣474. 一和零 474. 一和零 难度 中等 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&…

【Linux】权限(shell运行原理、概念,Linux权限)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12625432.html 目录 shell命令以及运行原理 创建和删除用户 创建新普通用户 删除用户 Linux权…

Unity中的UI系统之UGUI

目录 概述UGUI基础——六大基础组件六大基础组件概述Canvas画布组件CanvasScaler画布缩放控制器组件必备知识恒定像素模式缩放模式恒定物理模式3D模式 Graphic Raycaster图形射线投射器EventSystem和Standalone Input ModuleRectTransform UGUI基础——三大基础控件Image图像控…

混淆原理与实践指南

引言 &#x1f680; 在当今的软件开发领域&#xff0c;保护代码的安全性和保密性变得越来越重要。混淆&#xff08;Obfuscation&#xff09;技术作为一种保护代码的手段&#xff0c;在应对逆向工程和代码盗用方面发挥着关键作用。本文将深入探讨混淆的原理&#xff0c;以及如何…

javaWeb项目-财务管理系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Springboot框架 …

[lesson45]不同的继承方式

不同的继承方式 不同的继承方式 C中支持三种不同的继承方式 public继承 父类成员在子类中保持原有的访问级别 private继承 父类成员在子类中变为私有成员 protected继承 父类中公有成员变为保护成员&#xff0c;其他成员保持不变 遗憾的事实 一般而言&#xff0c;C工程项目…

镭眸T52激光雷达:无人叉车定位及避障新选择

在传统物料搬运领域&#xff0c;叉车虽扮演了重要角色&#xff0c;但人工操作的局限性——高昂的人力成本、有限的操作效率以及潜在的安全隐患&#xff0c;一直是企业面临的难题。随着劳动力成本的不断攀升&#xff0c;企业对降低成本、提升效率、减少安全事故的需求愈发迫切。…

【iOS开发】(四)react Native第三方组件五个20240419-20

react native 外的 第三方组件 目录标题 react native 外的 第三方组件&#xff08;一&#xff09;与rn核心组件的使用步骤区别&#xff1a;&#xff08;二&#xff09;第三方组件概览1 WebView2 Picker3 Swiper4 AsyncStorage5 Geolocation6 Camera (三)详细学习1 WebViewCoco…

Navicat 干货 | 掌握 PostgreSQL 规则语法

PostgreSQL 规则提供了一种强大的机制&#xff0c;控制查询执行并在数据库内部实施数据操作。理解规则的语法和用法对于有效利用其功能至关重要。在上周的文章中&#xff0c;我们探讨了 PostgreSQL 规则的工作原理及其与触发器的区别。今天的文章将使用免费的 “dvdrental”示例…

3.AlexNet--CNN经典网络模型详解(pytorch实现)

看博客AlexNet--CNN经典网络模型详解&#xff08;pytorch实现&#xff09;_alex的cnn-CSDN博客&#xff0c;该博客的作者写的很详细&#xff0c;是一个简单的目标分类的代码&#xff0c;可以通过该代码深入了解目标检测的简单框架。在这里不作详细的赘述&#xff0c;如果想更深…