【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     

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解锁EDM设计秘籍:关键要素一览,邮件如何设计?

一个成功的EDM邮件需要包含多个关键元素&#xff0c;从内容、设计到呼唤行动&#xff0c;每个环节都至关重要。今天&#xff0c;我们就来探讨EDM邮件中应包含的关键元素&#xff1f;以及如何设计邮件&#xff1f; 一、EDM必备关键要素 1、吸引眼球的主题行 主题行应该简短明了…

NC398 腐烂的苹果

腐烂的苹果 一个腐烂的苹果每分钟可以向上下左右四个方向扩展&#xff0c;扩展之后&#xff0c;又会有新的腐烂的苹果&#xff0c;一直去腐蚀好的苹果&#xff0c;求多少分钟后&#xff0c;网格中全是烂苹果。 第一次做这道题的时候&#xff0c;想到这道题考察的其实是多源BFS…

C#版Facefusion:让你的脸与世界融为一体!-04 人脸替换

C#版Facefusion&#xff1a;让你的脸与世界融为一体&#xff01;-04 人脸替换 目录 说明 效果 模型信息 项目 代码 下载 说明 C#版Facefusion一共有如下5个步骤&#xff1a; 1、使用yoloface_8n.onnx进行人脸检测 2、使用2dfan4.onnx获取人脸关键点 3、使用arcface_w60…

网络基础之-IP地址

文章目录 1. IP地址&#xff1a;网络和主机1.1 A类IP地址1.2 B类IP地址1.3 C类IP地址1.4 D类和E类IP地址 2.几个特殊的IP地址2.1 私有地址2.2网关 1. IP地址&#xff1a;网络和主机 IP地址是用于在计算机网络中唯一标识设备的一组数字。它由32位&#xff08;IPv4&#xff09;或…

05_Flutter屏幕适配

05_Flutter屏幕适配 一.屏幕适配方案 通过指定基准屏宽度&#xff0c;进行适配&#xff0c;基准屏宽度取决于设计图的基准宽度&#xff0c;以iphone 14 pro max为例&#xff0c; devicePixelRatio 物理宽度 / 逻辑宽度(基准宽度) iphone 14 pro max的物理尺寸宽度为1290&…

创新入门|解锁您的潜在市场:探秘付费点击广告(PPC)的秘密武器

在我们的营销领域&#xff0c;按点击付费 &#xff08;PPC&#xff09; 广告是增加流量、提高知名度并最终将点击转化为客户的基石策略。这种有针对性的广告模式&#xff0c;即企业只在点击广告时付费&#xff0c;彻底改变了公司投资在线推广的方式。尽管它看起来很简单&#x…

手写Promise实现

手写Promise实现 一、前言二、代码三、测试四、测试结果 一、前言 阅读参考资料&#xff0c;本文整理出使用 构造函数 手撕出 Promise 的方法&#xff0c;在整理过程中不断添加注解以示思路。有错请指出哟&#xff0c;一起进步&#xff01;&#xff01;&#xff01;class 实现 …

2024接口自动化测试入门基础知识【建议收藏】

接口自动化测试是指通过编写测试脚本和使用相关工具&#xff0c;对软件系统的接口进行自动化测试的过程。 今天本文从4个方面来介绍接口自动化测试入门基础知识 一、接口自动化测试是什么&#xff1f; 二、接口自动化测试流程&#xff1f; 三、接口自动化测试核心知识点有那些…

开始Java之旅

1.Java语言 java是一门优秀的程序设计语言&#xff0c;并且是一种半编译型&#xff0c;半解释型语言。 Java 语言源于 1991 年 4 月&#xff0c;Sun 公司 James Gosling博士 领导的绿色计划(Green Project) 开始启动&#xff0c;此计划最初的目标是开发一种能够在各种消费性电…

Threejs绘制传送带

接下来会做一个MES场景下的数字孪生&#xff0c;所以开始做车间相关的模型&#xff0c;不过还是尽量少用建模&#xff0c;纯代码实现&#xff0c;因为一方面可以动态使用&#xff0c;可以调节长度和宽度等&#xff0c; 下面这节就做一个简单的传送带&#xff0c;这是所有车间都…

学之思考试系统环境启动QA

学之思考试系统环境启动Q&A 目录 学之思考试系统环境启动Q&A后台代码启动失败:前台代码启动失败常见解决方式参考资料后台代码启动失败: 后端代码启动不成功,不能够自动导入maven,配置依赖; 使用idea打开到:\xzs-master\xzs-mysql-master\source\xzs这个路径下;…

函数的创建和调用及删除

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 函数和存储过程非常类似&#xff0c;也是可以存储在 Oracle 数据库中的 PL/SQL代码块&#xff0c;但是有返回值。 可以把经常使用的功能定义为一个函数&#xff0c;就像系统…

使用Flask部署ppocr模型_3

PaddleOCR环境搭建、模型训练、推理、部署全流程&#xff08;Ubuntu系统&#xff09;_1_paddle 多进程推理-CSDN博客 PP-Structure 文档分析-CSDN博客 Pycharm的Terminal进入创建好的虚拟环境 有时候Pycharm的terminal中显示的是硬盘中的项目路径&#xff0c;但没有进入创建好…

Python 开发实现登陆和注册模块

Python 开发实现登陆和注册模块 一、案例介绍 本例设计一个用户登录和注册模块&#xff0c;使用Tkinter框架构建界面&#xff0c;主要用到画布、文本框、按钮等组件。涉及知识点&#xff1a;Python Tkinter界面编程、pickle数据存储。本例实现了基本的用户登录和注册互动界面…

ic基础|时序篇:握手协议valid和ready的时序优化

大家好&#xff0c;我是数字小熊饼干&#xff0c;一个练习时长两年半的ic打工人。我在两年前通过自学跨行社招加入了IC行业。现在我打算将这两年的工作经验和当初面试时最常问的一些问题进行总结&#xff0c;并通过汇总成文章的形式进行输出&#xff0c;相信无论你是在职的还是…

网络安全的守护者:防火墙的五个主要功能解析

防火墙是一种网络安全设备&#xff0c;用于保护计算机网络免受未经授权的访问、攻击和恶意软件的侵害。它通过监控、过滤和控制网络流量&#xff0c;实施安全策略&#xff0c;防止不安全的数据包进入或离开受保护的网络。 防火墙的五个主要功能&#xff1a; 1. 访问控制&#…

Web入门-Tomecat

黑马程序员JavaWeb开发教程 文章目录 一、简介1、Web服务器2、Tomcat 二、基本使用三、入门程序解析 一、简介 1、Web服务器 对HTTP协议操作进行封装&#xff0c;简化web程序开发部署Web项目&#xff0c;对外提供网上信息浏览服务 2、Tomcat 概念&#xff1a;Tomcat是Apach…

(回溯)记忆化搜索和dp

动态规划的核心就是 状态的定义和状态的转移 灵神 的 回溯改递归思路 首先很多动态规划问题都可以采用 回溯 的思想 回溯主要思想就是把 一个大问题分解成小问题 比如 采用子集类回溯问题中的核心思想-> 选或不选 或者 选哪个 记忆化搜索之后 我们可以发现 每个新节点依…

深度图转点云

一、理论分析 二、其他分析 1、相机内参 相机内参主要是四个参数fx,fy,u0,v0。要明白相机内参就是相机内部参数&#xff0c;是参考像素坐标系而言&#xff0c;有了这个前提&#xff0c;这四个参数也就很好理解了。 &#xff08;1&#xff09;首先&#xff0c;。其中F是相机的…

sora related

官方https://openai.com/research/video-generation-models-as-world-simulators 概述&#xff1a; sora可以生成变长的、不同分辨率的最长可到1分钟的视频&#xff1b;整体流程是 v i d e o c o m p r e s s i o n n e r w o r k ( v i d e o → l a t e n t ) p a t c h i…