首页 > 其他分享 >单线程Reactor模型

单线程Reactor模型

时间:2024-04-10 22:59:03浏览次数:23  
标签:Reactor epoll 单线程 模型 server int handler fd client

1. 如何理解 reactor

reactor 是一种设计模式。用于处理事件驱动的系统。

reactor 模式,主要有两个组件:

reactor 反应器:负责监听所有事件,当事件发生时,调用相应的处理程序。reactor 本身时一个事件循环,负责处理 I/O 事件。

handler 处理程序:处理特点类型的事件。当 reactor 接收到事件时,他会调用相应的处理程序来执行具体的业务逻辑。

使用 epoll IO 多路复用实现一个阻塞对象监听多路连接请求。

说明:

  1. Reactor 对象通过 epoll 监听客户端请求,收到事件后通过 Dispatch 进行分发;
  2. 如果是建立连接的请求事件,则由 Acceptor 通过 Accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后续业务处理;
  3. 如果不是连接事件,则 Reactor 回调用连接对应的 Handler 来响应。
  4. Headler 会完成 Read -> 业务处理 -> Send 的完成业务流程。

优点:

模型简单,没有多线程,不存在资源竞争的问题。

缺点:

性能问题,只有一个线程,无法完全发挥多核 CPU 的性能。

当某个 Headler 阻塞时,会导致其他所有的 client 的 handler 都无法执行。

使用场景:

客户端数量有限,业务处理非常快速。

2. 实现单进程 reactor

#ifndef REACTOR_H
#define REACTOR_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <arpa/inet.h>

#define MAX_EVENTS 10
#define BUFFER_SIZE 1024

typedef struct {
    int fd;
    void (*callback)(int fd, int events, void *arg);
    int events;
    void *arg;
} EventHandler;

typedef struct {
    int server_fd;
    int epoll_fd;
    EventHandler *server_handler;
} TCPServer;

TCPServer *tcp_server_create(const char *ip, int port);
void dispathch(TCPServer *server);
void tcp_server_destroy(TCPServer *server);

static void handle_accept(int fd, int events, void *arg);
static void handle_read  (int fd, int events, void *arg);

#endif /* REACTOR_H */
#include "reactor.h"

static void handle_accept(int fd, int events, void *arg) {
    TCPServer *server = (TCPServer *)arg;
    int client_fd;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);
    if (client_fd == -1) {
        perror("Failed to accept connection");
        return;
    }
    printf("Connection established with %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

    EventHandler *client_handler = (EventHandler *)malloc(sizeof(EventHandler));
    client_handler->fd = client_fd;
    client_handler->events = EPOLLIN;
    client_handler->callback = handle_read;
    client_handler->arg = NULL;
    epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, client_fd, &(struct epoll_event){EPOLLIN, {.ptr = client_handler}});
}

static void handle_read(int fd, int events, void *arg) {
    char buffer[BUFFER_SIZE];
    int bytes_received = recv(fd, buffer, BUFFER_SIZE, 0);
    if (bytes_received <= 0) {
        if (bytes_received == 0) {
            printf("Connection closed by client\n");
        } else {
            perror("Failed to receive data from client");
        }
        close(fd);
        free(arg);
        return;
    }
    printf("Received data: %.*s\n", bytes_received, buffer);
    // Echo back the received data
    send(fd, buffer, bytes_received, 0);
}

TCPServer *tcp_server_create(const char *ip, int port) {
    TCPServer *server = (TCPServer *)malloc(sizeof(TCPServer));
    if (!server) {
        perror("Failed to allocate memory for server");
        return NULL;
    }

    // 创建 epoll 文件描述符
    server->epoll_fd = epoll_create1(0);
    if (server->epoll_fd == -1) {
        perror("Failed to create epoll file descriptor");
        free(server);
        return NULL;
    }

    // 创建服务器 socket
    server->server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server->server_fd == -1) {
        perror("Failed to create server socket");
        free(server);
        return NULL;
    }

    // 设置服务器 socket 选项
    int opt = 1;
    if (setsockopt(server->server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) == -1) {
        perror("Failed to set server socket options");
        close(server->server_fd);
        free(server);
        return NULL;
    }

    // 设置服务器地址信息
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(ip);
    server_addr.sin_port = htons(port);

    // 绑定服务器 socket
    if (bind(server->server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Failed to bind server socket");
        close(server->server_fd);
        free(server);
        return NULL;
    }

    // 监听服务器 socket
    if (listen(server->server_fd, SOMAXCONN) == -1) {
        perror("Failed to listen on server socket");
        close(server->server_fd);
        free(server);
        return NULL;
    }

    // 注册服务器 socket 处理程序到 epoll
    server->server_handler = (EventHandler *)malloc(sizeof(EventHandler));
    server->server_handler->fd = server->server_fd;
    server->server_handler->events = EPOLLIN;
    server->server_handler->callback = handle_accept;
    server->server_handler->arg = server;
    epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, server->server_fd, &(struct epoll_event){EPOLLIN, {.ptr = server->server_handler}});

    return server;
}

void dispathch(TCPServer *server) {
    struct epoll_event events[MAX_EVENTS];
    int event_count;
    printf("Server started. Waiting for connections...\n");
    while (1) {
        event_count = epoll_wait(server->epoll_fd, events, MAX_EVENTS, -1);
        if (event_count == -1) {
            perror("Failed to wait for events");
            break;
        }

        for (int i = 0; i < event_count; i++) {
            EventHandler *handler = events[i].data.ptr;
            if (handler->callback)
                handler->callback(handler->fd, handler->events, handler->arg);
        }
    }
}

void tcp_server_destroy(TCPServer *server) {
    close(server->server_fd);
    close(server->epoll_fd);
    free(server->server_handler);
    free(server);
}
#include "reactor.h"

int main() {
    TCPServer *server = tcp_server_create("127.0.0.1", 8888);
    if (!server) {
        fprintf(stderr, "Failed to create TCP server\n");
        return EXIT_FAILURE;
    }

    dispathch(server);
    tcp_server_destroy(server);

    return 0;
}

标签:Reactor,epoll,单线程,模型,server,int,handler,fd,client
From: https://blog.csdn.net/A152419/article/details/137613788

相关文章

  • 一文搞懂计算机视觉模型
    计算机视觉,这个曾经让科学家们望而生畏的领域,如今在深度学习的加持下,正迎来前所未有的发展。你是否好奇,是哪些深度学习模型让计算机拥有了“慧眼”?让我们一起揭开这些模型的神秘面纱。/1卷积神经网络(CNNs)。它们就像是视觉任务的万金油,无论是图像分类、目标检测还是人......
  • 基于PSO的NARMAX模型参数辨识算法matlab仿真
    目录1.算法仿真效果2.MATLAB源码3.算法概述4.部分参考文献1.算法仿真效果matlab2022a仿真结果如下:......
  • 大模型 RAG 是什么
    大模型RAG(Retrieval-AugmentedGeneration)是一种结合了检索(Retrieval)与生成(Generation)能力的先进人工智能技术,主要用于增强大型语言模型(LLMs,LargeLanguageModels)在特定任务中的表现,特别是那些需要访问外部知识库或实时信息的任务。RAG模型旨在克服LLMs存储容量有限、难以即......
  • 机器学习——常见模型评估指标
    目录一.模型评估综述1.1什么是模型评估1.2评估类型1.3模型泛化能力1.4过拟合与欠拟合1.4.1过拟合1.4.2欠拟合二.常见的分类模型评估方式2.1混淆矩阵2.2准确率(Accuracy)2.3精确率(Precision)2.4召回率(Recall)2.5F1-score2.6ROC曲线及AUC值2.7PR曲线三.PR曲线和ROC曲线的......
  • NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(Spider vs BIRD)全面对比
    NL2SQL基础系列(1):业界顶尖排行榜、权威测评数据集及LLM大模型(SpidervsBIRD)全面对比优劣分析[Text2SQL、Text2DSL]Text-to-SQL(或者Text2SQL),顾名思义就是把文本转化为SQL语言,更学术一点的定义是:把数据库领域下的自然语言(NaturalLanguage,NL)问题,转化为在关系型数据库中可以执行的......
  • new mars3d.graphic.PolylineEntity({实现航线真实穿过山体或者模型的部分用虚线展示
    1.在官网示例中通过 newmars3d.graphic.PolylineEntity({实现航线真实穿过山体或者模型的部分用虚线展示效果2.示例地址:功能示例(Vue版)|Mars3D三维可视化平台|火星科技3.实现效果: 1.航线真实穿过山体或者模型的部分用虚线展示、并且是(真实穿过不是视线挡住那种),遮挡......
  • 【转载】在SAP HANA中创建普通用户进行模型视图开发的权限设置
    转载自SAPComumunity模型视图是SAPHANA中一个重要的组成部分,它包括属性视图、分析视图以及计算视图。正确地使用模型视图进行开发,不仅能够在团队开发中使开发人员对业务理解能有更好的传递作用,也能够对业务场景进行加速,提高执行速度。相信读者之前对于模型视图的概念已经有了......
  • cpp 内存分区模型
    c++程序在执行前,将内存大方向划分为4个区域。1.代码区:存放函数的二进制代码,有操作系统进行管理2.全局区:存放全局变量和静态变量以及常量3.栈区:由编译器自动分配释放,存放的函数参数和局部变量4.堆区:由程序员分配释放,若程序员不分配释放,程序结束时由操作系统回收不同区域存......
  • 【TensorRT】TensorRT C# API 项目更新 (1):支持动态Bath输入模型推理(下篇)
    4.接口应用关于该项目的调用方式在上一篇文章中已经进行了详细介绍,具体使用可以参考《最新发布!TensorRTC#API:基于C#与TensorRT部署深度学习模型》,下面结合Yolov8-cls模型详细介绍一下更新的接口使用方法。4.1创建并配置C#项目 首先创建一个简单的C#项目,然后添加项......
  • 【大模型应用开发-FastAPI框架】(五)FastAPI 如何通过Poetry运行FastAPI应用程序
    一、概述FastAPI是一个现代、快速(高性能)的Web框架,用于构建API。Poetry是一个Python的依赖管理和打包工具,可以帮助我们更有效地管理项目的依赖和环境。在本文中,我们将介绍如何使用Poetry来运行FastAPI应用程序。二、安装FastAPI和Poetry在开始之前,我们需要先安装FastAPI和P......