最新资讯

  • C++项目:仿muduo库高并发服务器

C++项目:仿muduo库高并发服务器

2026-01-29 03:39:44 栏目:最新资讯 4 阅读


文章目录

  • 前言
  • 一、项目核心目标与定位
  • 二、Reactor模型
  • 三、功能模块划分
    • 3.1 SERVER模块
      • 3.1.1 Buffer模块
      • 3.1.2 Socket模块
      • 3.1.3 Channel模块
      • 3.1.4 Connection模块
      • 3.1.5 Acceptor模块
      • 3.1.6 TimerQueue模块
      • 3.1.7 Poller模块
      • 3.1.8 EventLoop模块
      • 3.1.8 TcpServer模块
  • 四、HTTPServer模块划分
    • 4.1 Util模块
    • 4.2 HttpRequest模块
    • 4.3 HttpResponse模块
    • 4.4 HttpContext模块
    • 4.5 HttpServer模块


码云链节

前言

若需要一手资料,可以私信博主添加好友
本文将为大家介绍博主学习制作的 “仿muduo库实现高并发服务器” 项目的前瞻知识。核心内容围绕两方面展开:一是帮助大家对该项目建立整体认知,明确项目的核心方向与大致框架;二是清晰交代本项目的学习目标及所需具备的知识储备,为大家后续制定学习计划、高效推进学习提供参考。

需要说明的是,文中内容均来自博主在学习该项目过程中所用资料的汇总与润色,力求为大家呈现准确、实用的前置信息。
学习该项目前首先确保已经掌握Http协议、Tcp协议、I/O多路转接技术等


一、项目核心目标与定位

本次项目旨在仿muduo库One Thread One Loop(一线程一循环)式主从Reactor模型,实现一款高并发服务器组件,具体目标与核心定位如下:

1. 核心功能目标

  • 基于经典的主从Reactor模型,采用muduo库标志性的One Thread One Loop线程模型,保障服务器的高并发处理能力;
  • 打造可复用的高并发服务器组件:开发者基于该组件,能以简洁、高效的方式快速搭建高性能基础服务器,无需重复实现底层网络通信与并发控制逻辑;
  • 提供应用层协议扩展支持:组件内置不同应用层协议适配能力(当前为便于演示,优先集成HTTP协议组件),支持开发者快速基于组件搭建高性能应用服务器(如HTTP服务器)。

2. 关键定位明确
需重点明确:本项目的核心产出是高并发服务器组件,而非包含具体业务逻辑的成品应用。组件聚焦于底层网络通信、并发调度、协议解析等通用能力的封装,不涉及实际业务内容。

二、Reactor模型

Reactor 模式,是服务器应对单客户端或多客户端并发请求时,采用的一种事件驱动式请求处理模式。其核心逻辑为:服务端程序先接收多路传入请求,再通过同步方式将这些请求分派至与请求一一对应的处理线程中执行处理。正因“分发请求”这一核心特性,Reactor 模式也被称为 Dispatcher 模式(分发者模式)。

若用更通俗的方式理解,Reactor模式的核心逻辑可概括为:借助I/O多路复用技术,对各类事件(如客户端连接请求、数据读写请求等)进行统一监听;一旦监听到事件触发,便将其精准分发给对应的处理进程或线程执行后续操作。

单Reactor单线程:单I/O多路复用+业务处理

  1. 通过IO多路复用模型进行客户端请求监控
  2. 触发事件后,进⾏事件处理
    a. 如果是新建连接请求,则获取新建连接,并添加⾄多路复⽤模型进行事件监控。
    b. 如果是数据通信请求,则进行对应数据处理(接收数据,处理数据,发送响应)。

优点: 所有操作均在同⼀线程中完成,思想流程较为简单,不涉及进程/线程间通信及资源争抢问题。
缺点: 所有的事件监控及业务处理都在一个线程中处理,⽆法有效利用CPU多核资源,很容易达到性能瓶颈。
适⽤场景: 适⽤于客户端数量较少,且处理速度较为快速的场景。(处理较慢或活跃连接较多,会导致串行处理的情况下,后处理的连接⻓时间⽆法得到响应)


单Reactor多线程:单I/O多路复用+线程池(业务处理)

  1. Reactor线程通过I/O多路复用模型进行客户端请求监控
  2. 触发事件后,进行事件处理
    a. 如果是新建连接请求,则获取新建连接,并添加⾄多路复用模型进行事件监控。
    b. 如果是数据通信请求,则接收数据后分发给Worker线程池进行业务处理。
    c. ⼯作线程处理完毕后,将响应交给Reactor线程进行数据响应

优点: 充分利⽤CPU多核资源,降低了代码耦合度
缺点: 多线程间的数据共享访问控制较为复杂,单个Reactor 承担所有事件的监听和响应,在单线程中运⾏,⾼并发场景下容易成为性能瓶颈(如:每时刻都有很多新客户端发起连接请求)。

单Reactor单线程模式中,Reactor线程需同时承担两项核心工作:一是监控各类请求事件(如客户端连接、数据到达等),二是直接对触发的请求进行处理。但实际场景中,请求处理往往需要消耗较长时间,这会导致Reactor线程被长期占用,无法及时响应新的事件,进而降低整体服务效率。
为解决这一问题,单Reactor多线程模式对职责进行了拆分优化:Reactor线程仅专注于事件监控与I/O数据操作——当检测到任务(如客户端请求)到来时,它只需通过I/O操作获取请求数据,随后便将完整的请求任务转交至专门的处理线程池;待线程池中的线程完成请求处理后,再由Reactor线程将处理结果转发回客户端。这种“I/O与业务处理分离”的设计,保证Reactor线程的响应及时性,也能通过线程池充分利用CPU资源,提升请求处理的并发能力。
但是再连接请求过多时,这种方法仍然存在性能瓶颈


多Reactor多线程:多I/O多路复用+线程池(业务处理)
解决当Reactor线程进行数据I/O时,无法响应连接请求

  1. 在主Reactor中处理新连接请求事件,新连接建立完成后分发到子Reactor中监控
  2. 在子Reactor中进行客户端通信监控,有事件触发,则接收数据分发给Worker线程池
  3. Worker线程池分配独立的线程进行具体的业务处理
    a. ⼯作线程处理完毕后,将响应交给子Reactor线程进行数据响应

优点: 充分利用CPU多核资源,主从Reactor各司其职

在多Reactor模式(通常包含主Reactor与从属Reactor)的设计中,职责分工更为明确:首先由主Reactor线程负责监听并创建新的客户端连接,一旦完成连接建立,便会将该连接转交至从属Reactor;此后,该连接的所有请求事件(如数据读写触发的事件)均由对应的从属Reactor负责监控与检测。

当从属Reactor检测到请求到来时,存在两种常见的处理设计方向:

  1. 从属Reactor直接处理:由监控该连接的从属Reactor线程,直接完成请求的处理逻辑;
  2. 转交线程池处理:从属Reactor仅负责获取请求数据,再将具体的业务处理任务交付给专门的处理线程池执行。

不过需注意,后一种“从属Reactor+线程池”的设计虽能进一步拆分I/O操作与业务逻辑,但需重点衡量线程频繁切换带来的额外成本,而且还需要考虑资源资源竞争问题,锁资源消耗较大,实现也比较复杂。

本项目实现主从Reactor模型服务器的设计逻辑如下:

  1. 主Reactor线程:专注新连接高效获取
    主Reactor线程仅承担单一核心任务——监控监听描述符(负责接收客户端连接请求的文件描述符),一旦检测到新的连接请求,便快速完成连接建立。这种“单一职责”设计能最大程度减少主Reactor的任务干扰,确保新连接获取的高效性。

  2. 子Reactor线程:负责通信事件与业务处理
    当主Reactor完成新连接建立后,会将该连接对应的描述符分发给子Reactor。此后,子Reactor线程将全程负责监控自身管理的描述符:一旦检测到读写事件(如客户端发送数据、连接关闭等),便直接执行数据的读写操作,并同步完成对应的业务逻辑处理,不交由线程池处理。

  3. 核心设计思想:One Thread One Loop
    整个服务器的线程与事件处理逻辑,围绕“One Thread One Loop”(一线程一循环)思想构建:每个线程内部都运行一个独立的事件处理循环(Loop),线程内的所有操作(如事件监控、I/O读写、业务处理)均在该循环中完成,一个线程严格对应一个事件循环。

前置知识:
时间轮定时器

三、功能模块划分

基于以上的理解,我们要实现的是⼀个带有协议支持的Reactor模型高性能服务器,因此将整个项目的实现划分为两个⼤的模块:

- SERVER模块: 实现Reactor模型的TCP服务器;
- 协议模块: 对当前的Reactor模型服务器提供应用层协议支持。

3.1 SERVER模块

SERVER模块的核心功能是对所有连接及线程进行统筹管理,确保各组件在合适时机执行对应操作,最终实现高性能服务器组件。其管理范畴具体分为三个方向:

  • 监听连接管理:对监听连接进行全生命周期管理
  • 通信连接管理:对已建立的通信连接进行维护与控制
  • 超时连接管理:对超时连接进行检测与处理

基于上述管理思想,SERVER模块可进行再次细化模块。

3.1.1 Buffer模块

  • 功能:用于实现通信套接字的用户态缓冲区
  • 意义:
    1. 防止接收到的数据不是一条完整的数据(提示:TCP面向字节流),因此对接收的数据进行缓冲
    2. 对客户端响应的数据,应该是在套接字可写的情况下进行发送
  • 功能设计:
    1. 向缓冲区中添加数据
    2. 从缓冲区中取出数据

buff模块的实现

3.1.2 Socket模块

Socket模块

  • 功能:对socket套接字的操作进行封装
  • 意义:在接下来的开发中,使我们对于套接字的各项操作更加简便,避免代码冗余
  • 功能设计:
    1. 创建套接字
    2. 绑定地址信息
    3. 开始监听
    4. 向服务器发起连接
    5. 获取新连接
    6. 接收数据
    7. 发送数据
    8. 关闭套接字
    9. 创建一个监听连接
    10. 创建一个客户端连接

3.1.3 Channel模块

  • 功能:对⼀个描述符需要进行的IO事件管理,实现对描述符可读,可写,错误…事件的管理操作,以及IO事件监控就绪后,根据不同的事件,回调不同的处理函数功能。
  • 意义:让描述符的监控事件在用户态更易维护,触发事件后的操作流程更清晰
  • 功能设计:
    1. 对监控事件的管理:
      • 描述符是否可读
      • 描述符是否可写
      • 对描述符监控可读
      • 对描述符监控可写
      • 解除可读事件监控
      • 解除可写事件监控
      • 解除所有事件监控
    2. 对监控事件触发后的处理:
      • 设置对于不同事件的回调处理函数,明确触发某个事件后该如何处理

Channel模块实现

3.1.4 Connection模块

Connection模块是对Buffer模块,Socket模块,Channel模块的⼀个整体封装,实现了对⼀个通信套接字的整体的管理,每⼀个进行数据通信的套接字(也就是accept获取到的新连接)都会使用Connection进行管理。

  • 功能:
    1. 是对通信连接进行整体管理的模块,连接相关操作均通过它执行
    2. 处理连接事件,因不知使用者事件处理逻辑,提供事件回调函数由使用者设置
  • 意义:并非单独功能模块,而是对连接做管理的模块,增加了连接操作的灵活性
  • 功能设计:
    1. 基础操作:关闭连接、发送数据、协议切换(本质就是重新设置回调函数)、启动非活跃连接超时释放、取消非活跃连接超时释放
    2. 回调函数设置:连接建立完成回调、新数据接收成功回调、连接关闭回调、任意事件回调

本项目只是实现了一个组件,组件的使用者具体进行什么操作我们是不知到的,所以在组件内部提供回调函数,让使用者自行选择,如:使用者自行调用服务端提供的回调函数处理,发送给服务端的数据

connection模块

3.1.5 Acceptor模块

  • 功能:对监听套接字进行管理
  • 意义:
    • 获取新建连接描述符后,为通信连接封装Connection对象并设不同回调
    • 因自身不知连接事件处理逻辑,通信连接的Connection封装、事件回调设置由服务器模块负责
  • 功能设计:
    • 回调函数设置:新建连接获取成功的回调设置,由服务器指定

这意思是Acceptor模块提供一个回调函数,在连接建立成功后,由服务器调用该回调函数完成对connection对象中的回调函数设置?

  • Acceptor模块角色:它主要聚焦在“获取新连接”这个动作流程里,负责当检测到有新连接进来时,能触发一个“钩子”(也就是它提供的回调函数入口 )。但它本身不关心拿到新连接后,具体要怎么初始化Connection里的各类事件回调(比如连接建立完成后的数据处理回调、异常处理回调等 )。
  • 服务器模块职责:服务器模块更清楚整个业务场景下,拿到新连接后需要让这个连接具备哪些“事件响应能力”,所以由服务器去实现具体的回调逻辑,在Acceptor触发“新建连接成功”的回调时,服务器把这些逻辑“填”到Connection对象里,让连接后续能按照业务需求处理各类事件,这样分工也让模块职责更清晰,解耦了连接获取和连接事件逻辑初始化的过程。简单说就是 Acceptor 搭好“通知有新连接”的架子,服务器负责往架子里填“新连接后续咋干活”的具体内容 。

这时博主自己学习时产生的疑问,问的AI

3.1.6 TimerQueue模块

TimerQueue模块是实现固定时间定时任务的模块,可以理解就是要给定时任务管理器,向定时任务管理器中添加⼀个任务,任务将在固定时间后被执行,同时也可以通过刷新定时任务来延迟任务的执行。

  • 功能:定时任务模块,让任务能在指定时间后执行
  • 意义:组件内部用于释放非活跃连接(希望非活跃连接在N秒后被释放 )
  • 功能设计:
    1. 添加定时任务
    2. 刷新定时任务(使定时任务重新开始计时 )
    3. 取消定时任务

这个模块主要是对Connection对象的⽣命周期管理,对非活跃连接进行超时后的释放功能。

3.1.7 Poller模块

  • 功能:对任意描述符进行IO事件监控
  • 意义:封装epoll,简化描述符事件监控操作
  • 功能接口:
    1. 添加事件监控(针对Channel模块 )
    2. 修改事件监控
    3. 移除事件监控

通过对epoll的封装达到对多个描述符同时检测的目的

3.1.8 EventLoop模块

  • 功能:
    1. 事件监控管理模块,是“one thread one loop”里的loop、reactor
    2. 一个模块对应一个线程
  • 意义:
    1. 负责服务器所有事件
    2. 每个Connection连接绑定一个EventLoop模块和线程,连接操作需在对应线程执行
  • 思想:
    1. 监控所有连接事件,事件触发后调用回调函数处理
    2. 连接操作放到EventLoop线程执行
  • 功能设计:
    1. 连接操作任务入队
    2. 定时任务增、刷、删

3.1.8 TcpServer模块

  • 功能:
    1. 整合所有子模块,供用户搭建高性能服务器
    2. 管理监听连接(新连接处理逻辑由Server设)
    3. 管理通信连接(连接事件处理逻辑由Server设)
    4. 管理超时连接(非活跃超时关闭逻辑由Server设)
    5. 管理事件监控(线程数、EventLoop数量由Server设)
    6. 设置事件回调函数(事件到来时该如何处理,由使用者设给TcpServer,再设给Connection )
  • 意义:让组件使用者更轻便搭建服务器

当有连接到来时,执行逻辑可总结为以下流程:

  1. Acceptor 模块触发:TcpServer 中的 Acceptor 模块监测到有新连接请求(可读事件等触发 ),代表新连接建立流程启动,获取新建连接的描述符。
  2. 创建 Connection 对象:利用获取到的连接描述符,封装创建 Connection 对象,用于后续对该连接的管理,同时会为其设置相关回调(如连接建立、数据收发等回调 ),并关联到 EventLoop 进行事件监控 。
  3. EventLoop 关联监控:将 Connection 对应的描述符相关事件(如可读、可写等 ),通过 Channel 模块注册到 EventLoop 中,由 EventLoop 依托 Poller 模块对这些 IO 事件进行监控管理 。
  4. 事件循环与处理:后续连接在生命周期内产生的各类事件(数据接收、可写、异常、关闭等 ),会被 EventLoop 检测到,触发 Channel 中设置的回调函数,进而执行 Connection 中或开发者自定义的对应逻辑(如数据解析、业务处理、资源清理等 ),实现对连接事件的响应和处理 。

至此,SERVER模块的组成部分已全部介绍完毕。接下来将进入SERVER模块功能的代码实现环节。 需要说明的是,为保证文章内容的连贯性,协议模块的组成相关内容将安排在后面。建议您先学习完SERVER模块的代码实现部分,再继续阅读协议模块的内容,以更好地理解整体逻辑衔接。

四、HTTPServer模块划分

由于应用层协议较多我们不可能全部实现,这里我们选择提供一种较为常见的协议支持:HTTP。用于对高并发服务器模块进行协议支持,基于其协议支持能更方便搭建指定协议服务器。

4.1 Util模块

工具模块,提供HTTP协议模块所用的工具函数

  • 功能:实现一些工具接口,具体包括读取文件内容、向文件写入内容、URL编码、URL解码、提供HTTP状态码&描述信息、根据文件后缀名获取mime。
  • 意义:在协议支持模块中,当需要某些零碎功能时,便于使用。
class Util{
    public:
    //分割字符串,以sep作为分割标志分割src,将分割后的字符串存入arry
    static size_t Split(const std::string &src,const std::string &sep,std::vector<std::string>*arry){
        int offset=0;//分割起始偏移量
        while(offset<src.size()){
            int pos=src.find(sep,offset);
            if(pos==std::string::npos){
                //添加最后一个字符
                arry->push_back(src.substr(offset));
                return arry->size();
            }
            if(pos==offset){//分割标志相连,不包含有效字符串
                offset=pos+sep.size();
                continue;
            }
            arry->push_back(src.substr(offset,pos-offset));
            offset=pos+sep.size();
        }
        return arry->size();
    }
        //读取文件的所有内容,将读取的内容放到一个Buffer中
        static bool ReadFile(const std::string &filename, std::string *buf) {
            //ERR_LOG("%s,%ld",filename.c_str(),filename.size());

            std::ifstream ifs(filename, std::ios::binary);
            if (ifs.is_open() == false) {
                printf("OPEN %s FILE FAILED!!", filename.c_str());
                return false;
            }
            size_t fsize = 0;
            ifs.seekg(0, ifs.end);//跳转读写位置到末尾
            fsize = ifs.tellg();  //获取当前读写位置相对于起始位置的偏移量,从末尾偏移刚好就是文件大小
            ifs.seekg(0, ifs.beg);//跳转到起始位置
            buf->resize(fsize); //开辟文件大小的空间
            ifs.read(&(*buf)[0], fsize);
            if (ifs.good() == false) {
                printf("READ %s FILE FAILED!!", filename.c_str());
                ifs.close();
                return false;
            }
            //ERR_LOG("%ld",buf->size());
            ifs.close();
            return true;
        }
        //向文件写入数据
        static bool WriteFile(const std::string &filename, const std::string &buf) {
            //ERR_LOG("0000000    %ld",buf.size());
            std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
            if (ofs.is_open() == false) {
                printf("OPEN %s FILE FAILED!!", filename.c_str());
                return false;
            }
            ofs.write(buf.c_str(), buf.size());
            if (ofs.good() == false) {
                ERR_LOG("WRITE %s FILE FAILED!", filename.c_str());
                ofs.close();    
                return false;
            }
            ofs.close();
            return true;
        }

    //URL编码
    //编码目的:避免URL中资源路径与查询字符串里的特殊字符和HTTP请求中的特殊字符产生歧义。
    //编码格式:把特殊字符的ASCII值,转换成两个十六进制字符,前缀为`%`,例如`C++`编码后为`C%2B%2B`。
    //不编码字符:依据RFC3986文档,`.`、`-`、`_`、`~`以及字母、数字属于绝对不编码的字符。
    //空格编码特殊规定:在w3C标准里,查询字符串中的空格需要编码为`+`,解码时`+`转换为空格。
    static std::string UrlEncode(const std::string&str,bool convert_space_to_plus){
        std::string res;
        for(auto c:str){
            if(c=='.'||c=='-'||c=='_'||c=='~'||isalnum(c)){
                res+=c;
                continue;
            }
            if(c==' '&&convert_space_to_plus){
                res+='+';
                continue;
            }
            char tmp[4]={0};
            snprintf(tmp,4,"%%%02X",c);
            res+=tmp;
        }
        return res;
    }
    static char HEXTOI(char c){
        if(c>='0'&&c<='9'){
            return c-'0';
        }
        if(c>='a'&&c<='z'){
            return c-'a'+10;
        }
        if(c>='A'&&c<='Z'){
            return c-'A'+10;
        }
        return -1;
    }
    //URL解码
    static std::string UrlDecode(const std::string&str,bool convert_space_to_plus){
        std::string res;
        int n=str.size();
        for(int i=0;i<n;i++){
            if(str[i]=='+'&&convert_space_to_plus){
                res+=' ';
                continue;
            }
            if(str[i]=='%'){
                char v1=HEXTOI(str[i+1]);
                char v2=HEXTOI(str[i+2]);
                char v=v1*16+v2;
                res+=v;
                i+=2;
                continue;
            }
            res+=str[i];
        }
        return res;
    }
    //获取响应状态码的描述信息
    static std::string StatuDesc(int statu){

        auto it=_statu_msg.find(statu);
        if(it==_statu_msg.end()){
            return "Unknow";
        }
        return it->second;
    }
    //根据文件后缀名获取文件的mime
    static std::string ExtMime(const std::string&filename){
        
        int pos=filename.find_last_of('.');
        if(pos==std::string::npos){
            return "application/octet-stream";//二进制流数据,表示不确定类型的文件
        }
        //根据扩展名获取mime
        auto it=_mime_msg.find(filename.substr(pos));
        if(it==_mime_msg.end()){
            return "application/octet-stream";
        }
        return it->second;
    }
    //判断一个文件是否是目录
    static bool IsDirectory(const std::string&filename){
        struct stat st;//用于存储文件或目录的相关信息
        int ret=stat(filename.c_str(),&st);
        if(ret<0){
            ERR_LOG("STAT FAIL!");
            return false;
        }
        return S_ISDIR(st.st_mode);//检查 stat 结构体中的 st_mode 字段是否表示一个目录
    }
    //判断一个文件是否是普通文件
    static bool IsRegular(const std::string&filename){
        struct stat st;//用于存储文件或目录的相关信息
        int ret=stat(filename.c_str(),&st);
        if(ret<0){
            ERR_LOG("STAT FAIL!");
            return false;
        }
        return S_ISREG(st.st_mode);//检查 stat 结构体中的 st_mode 字段是否表示一个目录
    }
    //http请求的资源路径有效性判断
    //http请求的资源路径有效性判断
    // /index.html --- 前边的/叫做相对根目录 映射的是某个服务器上的子目录
    // 想表达的意思就是,客户端只能请求相对根目录中的资源,其他地方的资源都不予理会
    static bool ValidPath(const std::string&path) {
        //思想:按照/进行路径分割,根据有多少个计算目录深度
        std::vector<std::string> subdir;
        Split(path,"/",&subdir);
        int level=0;
        for(auto& sdir:subdir){
            if(sdir==".."){
                level--;
                if(level<0)return false;
                continue;
            }
            level++;
        }
        return true;
    }

};

4.2 HttpRequest模块

HTTP请求数据模块,保存HTTP请求数据解析后的各项请求元素信息

  • 功能:存储HTTP请求信息,具体是接收到一个数据后,按照HTTP请求格式进行解析,将得到的各个关键要素放到HttpRequest中。
  • 意义:让HTTP请求的分析更加简单。
  • 要素:包含URL(涉及请求方法、资源路径、查询字符串)、协议版本、头部字段、正文。
  • 接口:提供头部字段的插入和获取、查询字符串的插入和获取功能。
//存储http请求信息
class HttpRequest
{
public:
    HttpRequest():_version("HTTP/1.1"){}
    // 重新设置请求信息
    void ReSetRequest(){
        _method.clear();
        _path.clear();
        _version="HTTP/1.1";
        _body.clear();
        std::smatch smatch;
        _smatch.swap(smatch);
        _headers.clear();
        _params.clear();
    }
    //设置解析出来的头部字段
    void SetHeader(const std::string&key,const std::string&val){
        _headers.insert({key,val});
    }
    //指定头部字段是否存在
    bool HasHeader(const std::string&key){
        auto it=_headers.find(key);
        if(it==_headers.end()){
            return false;
        }
        return true;
    }
    //获取指定字段的val
    std::string GetHeader(const std::string&key){
        auto it=_headers.find(key);
        if(it==_headers.end()){
            return "";
        }
        return it->second;
    }
    //设置解析出来的查询字符串
    void SetParam(const std::string&key,const std::string&val){
        _params.insert({key,val});
    }
    //判断指定查询字符串是否存在
    bool HasParam(const std::string&key){
        auto it=_params.find(key);
        if(it==_params.end()){
            return false;
        }
        return true;
    }
    //获取指定查询字符串
    std::string GetParam(const std::string&key){
        auto it=_params.find(key);
        if(it==_params.end()){
            return "";
        }
        return it->second;
    }
    //获取正文大小

    size_t ContentLength(){
        //从头部字段中获取
        if(!_headers.count("Content-Length")){
            return 0;
        }
        std::string clen=_headers["Content-Length"];
        return std::stol(clen);
    }
    //判断该是否是短连接
    //没有Connection字段或者说Connection字段的是close都是短连接
    bool Close(){
        if(HasHeader("Connection")&&_headers["Connection"]=="keep-alive"){
            return false;
        }
        return true;
    }
public:
    std::string _method;//请求方法
    std::string _path;//资源路径
    std::string _version;//协议版本
    std::string _body;//请求正文
    std::smatch _smatch;//资源路径的正则提取数据
    std::unordered_map<std::string,std::string> _headers;//头部字段
    std::unordered_map<std::string,std::string> _params;//查询字符串
};

4.3 HttpResponse模块

HTTP响应数据模块,业务处理后设置并保存HTTP响应数据的各项元素信息,最终按HTTP协议响应格式组织成响应信息发送给客户端。

  • 功能:存储HTTP响应信息;在进行业务处理的同时,让使用者向HttpResponse中填充响应要素,完毕后,将其组织成为HTTP响应格式的数据,发送给客户端。
  • 意义:让HTTP响应的过程变得简单。
  • 要素:包含协议版本、响应状态码、状态码描述信息、头部字段、正文。
  • 接口:提供头部字段的插入和获取、长连接&短链接的设置与判断、正文的设置功能。

std::smatch:保存首行使用regex正则进行解析后所提取的数据,比如提取资源路径中的数字等。

//HttpResponse:存储响应信息
class HttpResponse{
    public:
    HttpResponse():_statu(200),_redirect_flag(false)
    {}
    HttpResponse(int statu):_statu(statu),_redirect_flag(false)
    {}
    //重新设置响应信息
    void ReSetResponse(){
        _statu=200;
        _redirect_flag=false;
        _body.clear();
        _redirect_url.clear();
        _headers.clear();
    }
    //设置头部
    void SetHeader(const std::string&key,const std::string&val){
        _headers.insert({key,val});
    }
        //指定头部字段是否存在
    bool HasHeader(const std::string&key){
        auto it=_headers.find(key);
        if(it==_headers.end()){
            return false;
        }
        return true;
    }
    //获取指定字段的val
    std::string GetHeader(const std::string&key){
        auto it=_headers.find(key);
        if(it==_headers.end()){
            return "";
        }
        return it->second;
    }

    //设置正文信息
    void SetContent(const std::string&body,const std::string&type){
        _body=body;
        SetHeader("Content-Type",type);  
    }
    //设置重定向路径,302:临时重定向
    void SetRedirect(const std::string&url,int statu=302){
        _redirect_url=url;
        _statu=statu;
        _redirect_flag=true;
    }
    //判断该是否是短连接
    //没有Connection字段或者说Connection字段的是close都是短连接
    bool Close(){
        if(HasHeader("Connection")&&_headers["Connection"]=="keep-alive"){
            return false;
        }
        return true;
    }
    public:
    int _statu;//响应状态码
    bool _redirect_flag;//是否重定向标志
    std::string _body;//响应正文
    std::string _redirect_url;//重回定向路径
    std::unordered_map<std::string,std::string> _headers;//响应头部
};

4.4 HttpContext模块

HTTP请求接收的上下文模块,防止一次接收的数据不是完整HTTP请求导致解析未完成,需在下次接收新数据后根据上下文继续解析,最终得到完整HttpRequest请求信息对象,用于控制请求数据的接收及解析节奏。

  • 请求接收上下文模块

    • 功能:记录HTTP请求的接收和处理进度。
    • 意义:因可能接收的不是完整HTTP请求数据,请求处理需多次收数据后完成,所以每次处理要记录进度,以便下次从当前进度继续。
    • 要素
      • 接收状态:包括接收请求行(当前处于接收并处理请求行的阶段)、接收请求头部(表示请求头部的接收还没有完毕)、接收正文(表示还有正文没有接收完毕)、接收数据完毕(接收完毕,可对请求进行处理的阶段)、接收处理请求出错。
      • 响应状态码:在请求接收并处理中,可能出现解析出错、访问资源不对、没有权限等不同问题,对应错误的响应状态码不同。
  • 接收并处理请求数据及接口相关

    • 实现
      • 已接收并处理的请求信息。
      • 接收并处理请求数据:包含接收请求行、解析请求行、接收头部、解析头部、接收正文。
    • 接口
      • 返回解析完毕的请求信息。
      • 返回响应状态码。
      • 返回接收解析状态。
typedef enum{
    RECV_HTTP_ERR,
    RECV_HTTP_LINE,
    RECV_HTTP_HEAD,
    RECV_HTTP_BODY,
    RECV_HTTP_OVER
}HttpRecvStatu;
//存储http请求解析的信息
#define MAX_LINE 8192
class HttpContent{
private:
    //接收请求行
    bool RecvHttpLine(Buffer*buf){
        //判断请求处理阶段是否为首行处理
        if(_recv_statu!=RECV_HTTP_LINE)return false;

        //从接收缓冲区中获取请求行
        std::string line = buf->GetLineAndPop();
        if(line.size()==0){
            //未接收到,判断缓冲区数据是否很长且没有‘/n’
            if(buf->ReadAbleSize()>MAX_LINE){
                _recv_statu=RECV_HTTP_ERR;
                _resp_statu=414;//URI Too Long
                return false;
            }
            //缓冲区不足一行,等待数据到来
            return true;
        }
        //接收到数据了,但是请求行过长
        if(line.size()>MAX_LINE){
            _recv_statu=RECV_HTTP_ERR;
            _resp_statu=414;//URI Too Long
            return false;
        }
        bool ret=ParseHttpLine(line);
        if(ret==false){
            return false;
        }
        //首行处理完毕进入头部处理阶段
        _recv_statu=RECV_HTTP_HEAD;
        return true;
    }
    //解析Http请求头部
    bool ParseHttpLine(const std::string &line){
        // http请求行格式:GET/bitejiuyeke/login?user=xiaoming&pass=123123 HTTP/1.1

        std::smatch matchs; // 存储提取数据
        // 匹配任意字符串并提取GET|DELETE|PUT|POST|HEAD
        //[^?]:表示匹配非?字符  *,表示匹配零次或多次
        //?匹配普通字符?,在正则表达式中?表示匹配0次或1次因此需要转译
        //(HTTP/1.[01]):匹配以HTTP/1.开始后边为0或1的字符串

        //std::regex::icase进行匹配时不区分大小写
        //?:表示它所处括号内容只匹配不捕获?表示匹配0次或1次
        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:?(.*))? (HTTP/1.[01])(?:
|
)?", std::regex::icase);
        //解析得到的结果
        // 0 :GET/bitejiuyeke/login?user=xiaoming&pass=123123 HTTP/1.1
        // 1 :GET
        // 2 :/bitejiuyeke/login
        // 3 :user=xiaoming&pass=123123
        // 4 :HTTP/1.1
        bool ret = regex_match(line, matchs, e);
        if (!ret){
            _recv_statu=RECV_HTTP_ERR;
            _resp_statu=400;
            ERR_LOG("REGEX PARSE HTTP LINE FAIL!");
            return false;
        }
        // std::cout << matchs[0] << std::endl;
        // std::cout << matchs[1] << std::endl;
        // std::cout << matchs[2] << std::endl;
        // std::cout << matchs[3] << std::endl;
        // std::cout << matchs[4] << std::endl;
        _request._method=matchs[1];

        //:: 表示引用全局接口
        std::transform(_request._method.begin(),_request._method.end(),_request._method.begin(),::toupper);
        _request._path=Util::UrlDecode(matchs[2],true);
        _request._version=matchs[4];
        std::string query_string=matchs[3];
        std::vector<std::string> query_string_arry;
        Util::Split(query_string,"&",&query_string_arry);
        for(auto &str:query_string_arry){
            int pos=str.find('=');
            if(pos==std::string::npos){
                _recv_statu = RECV_HTTP_ERR;
                _resp_statu = 400;
                ERR_LOG("REGEX PARSE HTTP LINE FAIL!");
                return false;
            }
            std::string key=str.substr(0,pos);
            std::string val=str.substr(pos+1);
            _request.SetParam(key,val);
        }
        return true;
    }
    //接收http请求头部
    bool RecvHttpHead(Buffer*buf){
        //判断请求处理阶段是否为头部处理
        if(_recv_statu!=RECV_HTTP_HEAD)return false;
        while(1){

            // 从接收缓冲区中获取请求头部
            std::string line = buf->GetLineAndPop();
            if (line.size() == 0){
                // 未接收到,判断缓冲区数据是否很长且没有‘/n’
                if (buf->ReadAbleSize() > MAX_LINE)
                {
                    _recv_statu = RECV_HTTP_ERR;
                    _resp_statu = 414; // URI Too Long
                    return false;
                }
                // 缓冲区不足一行,等待数据到来
                return true;
            }
            // 接收到数据了,但是头部过长
            if (line.size() > MAX_LINE){
                _recv_statu = RECV_HTTP_ERR;
                _resp_statu = 414; // URI Too Long
                return false;
            }
            //判断头部是否处理完毕
            if(line=="
"||line=="
"){
                //处理完毕进入正文处理阶段
                _recv_statu=RECV_HTTP_BODY;
                return true;
            }
            //进入头部解析
            int ret=ParseHttpHead(line);
            if(ret==false){
                return false;
            }
        }
        _recv_statu=RECV_HTTP_BODY;
        return true;

    }
    //解析Http头部
    bool ParseHttpHead(std::string&line){
        //key: val
....
        if(line.back()=='
') line.pop_back();
        if(line.back()=='
') line.pop_back();
        int pos = line.find(": ");
        if (pos == std::string::npos){
            _recv_statu = RECV_HTTP_ERR;
            _resp_statu = 400;
            ERR_LOG("PARSEHTTPHEAD FAIL!");
            return false;
        }
        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos +2);
        _request.SetHeader(key, val);
        return true;
    }
    //接收请求正文
    bool RecvHttpBody(Buffer*buf){
        if(_recv_statu!=RECV_HTTP_BODY)return false;
        //获取请求正文大小
        int content_length=_request.ContentLength();
        if(content_length==0){//请求没有正文
            _recv_statu=RECV_HTTP_OVER;
            return true;
        }
        //计算实际还需获取的长度
        int real_length=content_length-_request._body.size();
        //判断缓冲区的数据能否提供完整的正文
        if(buf->ReadAbleSize()>=real_length){
            //获取正文
            _request._body.append(buf->ReadPosition(),real_length);
            _recv_statu=RECV_HTTP_OVER;
            buf->MoveReadOffset(real_length);
            return true;
        }
        //缓冲区正文不完整
        _request._body.append(buf->ReadPosition(), buf->ReadAbleSize());
        buf->MoveReadOffset(buf->ReadAbleSize());
        return true;
    }
public:
    HttpContent():_resp_statu(200),_recv_statu(RECV_HTTP_LINE){}
    //获取响应状态码
    int RespStatu(){
        return _resp_statu;
    }
    //获取当前解析得到的请求信息
    HttpRequest& Request(){
        return _request;
    }
    //获取当前请求接收状态
    HttpRecvStatu RecvStatu(){
        return _recv_statu;
    }
    //接收并解析http请求
    void HttpRecvRequest(Buffer*buf){
        switch(_recv_statu){
            case RECV_HTTP_LINE: RecvHttpLine(buf);
            case RECV_HTTP_HEAD: RecvHttpHead(buf);
            case RECV_HTTP_BODY: RecvHttpBody(buf);
        };
        //std::cout<<_request._method<<" "<<_request._path<<" ";
        return;
    }
    void ReSetRecvContent(){
        _resp_statu=200;
        _recv_statu=RECV_HTTP_LINE;
        _request.ReSetRequest();
    }
public:
    int _resp_statu;//http响应状态
    HttpRecvStatu _recv_statu;//当前http接收状态
    HttpRequest _request;//当前已解析得到的http请求
};

4.5 HttpServer模块

这个模块综合了前面几个模块的功能,实现起来比较复杂
给组件使用者提供的HTTP服务器模块,以简单接口实现HTTP服务器搭建。内部包含一个TcpServer对象(TcpServer对象实现服务器的搭建);包含两个提供给TcpServer对象的接口:连接建立成功设置上下文接口、数据处理接口;还包含一个hash - map表存储请求与处理函数的映射表

  • 请求路由表设计目的:记录针对具体请求应使用哪个函数进行业务处理的映射关系。
  • 工作流程:服务器收到请求后,在请求路由表中查找是否有对应请求的处理函数,若有则执行该函数。
  • 核心逻辑:“什么请求,怎么处理”由用户设定,服务器收到请求只需执行对应函数。
  • 好处:用户只需实现业务处理函数,并将请求与处理函数的映射关系添加到服务器;服务器只需负责接收数据、解析数据、查找路由表映射关系、执行业务处理函数。

所需要素

  1. 请求路由映射表:涵盖 GET、POST、PUT、DELETE 请求的路由映射表,用于记录对应请求方法的处理函数映射关系,以处理功能性请求。
  2. 静态资源相对根目录:用于实现静态资源(如 html、图片等实体文件)请求的处理。
  3. 高性能 TCP 服务器:负责连接的 IO 操作。

服务器处理流程

  • 从 socket 接收数据,放到接收缓冲区。

  • 调用 OnMessage 回调函数进行业务处理。

  • 解析请求,得到包含所有请求要素的 HttpRequest 结构。

  • 进行请求路由查找,确定对应请求的处理方法:

    • 静态资源请求:读取静态资源文件数据,填充到 HttpResponse 结构中。
    • 功能性请求:在请求路由映射表中查找处理函数,找到则执行该函数,进行具体业务处理并填充 HttpResponse 结构。
  1. 对静态资源请求或功能性请求处理完毕后,得到填充了响应信息的 HttpResponse 对象,组织成 HTTP 格式的响应并进行发送。

相关接口

  1. 可进行添加请求 - 处理函数映射信息(支持 GET、POST、PUT、DELETE 等请求类型)、设置静态资源根目录、设置是否启动超时连接关闭、设置线程池中线程数量、启动服务器等操作。
  2. 还有 OnConnected(用于给 TcpServer 设置协议上下文)、OnMessage(用于进行缓冲区数据解析处理)等回调相关接口,以及请求的路由查找(包含静态资源请求查找和处理、功能性请求的查找和处理)、组织响应进行回复等功能接口。
class HttpServer{
using Handler=std::function<void(const HttpRequest&,HttpResponse*)>;
using Handlers=std::vector<std::pair<std::regex,Handler>>;
private:
    //将HttpReponse中的数据组织成http格式并返回
    void WriteReponse(const PtrConnection&conn,HttpRequest&req,HttpResponse&rsp){
        //构建头部
        if(req.Close()==true){
            rsp.SetHeader("Connection","close");
        }
        else{
            rsp.SetHeader("Connection","keep-alive");
        }
        if(!rsp._body.empty()&&rsp.HasHeader("Content-Length")==false){
            rsp.SetHeader("Content-Length",std::to_string(rsp._body.size()));
        }
        if(!rsp._body.empty()&&rsp.HasHeader("Content-Type")==false){
            rsp.SetHeader("Content-Type","application/octet-stream");
        }
        if(rsp._redirect_flag){
            rsp.SetHeader("Location",rsp._redirect_url);
        }
        //将rsp的数据组织为http响应
        std::stringstream rsp_str;
        rsp_str<<req._version<<" "<<std::to_string(rsp._statu)<<" "<<Util::StatuDesc(rsp._statu)<<"
";
        for(auto &it:rsp._headers){
            rsp_str<<it.first<<": "<<it.second<<"
";
        }
        rsp_str<<"
";
        rsp_str << rsp._body;
        //发送响应
        std::cout << "已发送响应: " << rsp_str.str() << std::endl;
        conn->Send(rsp_str.str().c_str(),rsp_str.str().size());
        return;
    }
    //静态资源的处理
    void FileHandler(const HttpRequest&req,HttpResponse* rsp){
        std::string buf;
        int ret=Util::ReadFile(req._path,&buf);
        if(ret==false){
            return ;
        }
        rsp->_body=buf;
        std::string mime=Util::ExtMime(req._path);
        rsp->SetHeader("Content-Type",mime);
        return ;
    }
    //功能性请求的分发
    void Dispatcher(HttpRequest&req,HttpResponse* rsp,const Handlers&handlers){
        // 在对应请求方法的路由表中,查找是否含有对应资源请求的处理函数,有则调用,没有则返回 404。
        // 思想:路由表存储正则表达式与处理函数的键值对,使用正则表达式对请求的资源路径进行正则匹配,匹配成功就用对应函数处理。
        // 示例:/numbers/(d+) 可匹配 /numbers/12345。
        for(auto&handler:handlers){
            std::regex re=handler.first;
            bool ret=std::regex_match(req._path,req._smatch,re);
            if(ret==false){
                continue;
            }
            handler.second(req,rsp);
            return;
        }
        rsp->_statu=404;
    }
    //判断请求是否为静态资源请求
    bool IsFileHandler(HttpRequest&req){
        //保证设置了静态资源根目录
        if(static_basedir.empty()){
            return false;
        }
        //请求方法必须是GET或HEAD
        if(req._method!="GET"&&req._method!="HEAD"){
            return false;
        }
        //请求资源路径必须合法
        if(Util::ValidPath(req._path)==false){
            return false;
        }
        //请求资源必须存在,且是一个合法路径
        // 检测请求路径中是否包含根目录前缀:判断req._path是否以服务器根目录前缀(如/wwwroot/)开头。
        // 拼接正确路径:用处理后的相对路径与服务器根目录拼接,得到实际路径。
            
        std::string req_path=static_basedir+req._path;
        std::cout <<  "资源路径是:"  << req_path << "xxx"<< std::endl;
        if(req_path.back()=='/'){
            req_path+="index.html";
        }
           std::cout <<  "资源路径是:"  << req_path << "xxx"<< std::endl;
        if(Util::IsRegular(req_path)!=true){
            return false;
        }
        req._path=req_path;
        return true;
    }
    //路由表查询划分
    void Route(HttpRequest&req,HttpResponse* rsp){
        //对请求进行分辨
        //GET HEAD 默认为静态资源请求
        //如果不是静态请求也不是动态请求设置状态405
        if(IsFileHandler(req)){
            //静态资源请求
            FileHandler(req,rsp);
            return;
        }
        if(req._method=="GET"||req._method=="HEAD"){
            Dispatcher(req,rsp,_get_route);
            return;
        }
        
        if(req._method=="POST"){
            ERR_LOG("POST ....");
            Dispatcher(req,rsp,_post_route);
            return;
        }
        if(req._method=="PUT"){
            Dispatcher(req,rsp,_put_route);
            return;
        }
        if(req._method=="DELETE"){
            Dispatcher(req,rsp,_delete_route);
            return;
        }

        rsp->_statu=405;// Method Not Allowed
        return;
    }
    //初始化上下文数据
    void OnConnected(const PtrConnection&conn){
        conn->SetContext(HttpContent());
    }
    //对请求解析并处理
    void OnMessage(const PtrConnection&conn,Buffer*buf){
        while(1){
            // 1.获取上下文
            HttpContent *content = conn->GetContext()->get<HttpContent>();
            // 2.通过上下文对缓冲区数据进行解析,得到HttpRequest
            content->HttpRecvRequest(buf);
            HttpResponse rsp(content->_resp_statu);
            HttpRequest &req = content->Request();
            if(content->_resp_statu>=400){
                ERR_LOG("HTTPRECVREQUEST FAIL!");
                // 缓冲区数据解析失败,构建错误信息
                ErrorHandler(req,&rsp);
                buf->MoveReadOffset(buf->ReadAbleSize());
                // 返回响应
                WriteReponse(conn, req, rsp);
                content->ReSetRecvContent();
                conn->Shutdown();
            }
            if (content->_recv_statu != RECV_HTTP_OVER){
                
                return;
            }
            // 3.请求路由+业务处理
            Route(req, &rsp);
            // 4.对HttpResponse进行业务发送
            WriteReponse(conn, req, rsp);
            // 5.重置上下文
            content->ReSetRecvContent();
            // 6.判断长短连接
            if (rsp.Close() == true){ // 短连接直接关闭
                conn->Shutdown();
                return;
            }
        }
    }
    void ErrorHandler(const HttpRequest &req, HttpResponse *rsp) {
        // 组织一个错误展示页面
        std::string body;
        body += "";
        body += "";
        body += "";
        body += "";
        body += "";
        body += "

"; body += std::to_string(rsp->_statu); body += " "; body += Util::StatuDesc(rsp->_statu); body += "

"
; body += ""; body += ""; // 将页面数据当作响应正文放入rsp中 rsp->SetContent(body, "text/html"); } public: HttpServer(int port,int timeout=DEFALT_TIMEOUT):_server(port){ _server.EnableInactiveRelease(timeout);//http服务默认启动超时销毁 _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected,this,std::placeholders::_1)); _server.SetMessageCallback(std::bind(&HttpServer::OnMessage,this,std::placeholders::_1,std::placeholders::_2)); } //设置路由表 // using Handler=std::function; // using Handlers=std::vector>; void Get(const std::string&pattern,const Handler&handler){ _get_route.push_back(std::make_pair(std::regex(pattern),handler)); } void Post(const std::string&pattern,const Handler&handler){ _post_route.push_back(std::make_pair(std::regex(pattern),handler)); } void Put(const std::string&pattern,const Handler&handler){ _put_route.push_back(std::make_pair(std::regex(pattern),handler)); } void Delete(const std::string&pattern,const Handler&handler){ _delete_route.push_back(std::make_pair(std::regex(pattern),handler)); } //设置线程数量 void SetThreadCount(int count){ _server.SetThreadCount(count); } //设置静态资源根目录 void SetBasedir(const std::string&path){ assert(Util::IsDirectory(path)); static_basedir=path; } //启动服务器 void Listen(){ _server.Start(); } private: std::string static_basedir;//静态资源根目录 Handlers _get_route;//GET的请求路由映射表 Handlers _post_route;//POST的请求路由映射表 Handlers _put_route;//put的请求路由映射表 Handlers _delete_route;//delete的请求路由映射表 TcpServer _server; };

本文地址:https://www.yitenyun.com/1271.html

搜索文章

Tags

#服务器 #python #pip #conda #ios面试 #ios弱网 #断点续传 #ios开发 #objective-c #ios #ios缓存 #人工智能 #微信 #远程工作 #Trae #IDE #AI 原生集成开发环境 #Trae AI #kubernetes #笔记 #平面 #容器 #linux #学习方法 香港站群服务器 多IP服务器 香港站群 站群服务器 #运维 #学习 #银河麒麟高级服务器操作系统安装 #银河麒麟高级服务器V11配置 #设置基础软件仓库时出错 #银河麒高级服务器系统的实操教程 #生产级部署银河麒麟服务系统教程 #Linux系统的快速上手教程 #分阶段策略 #模型协议 #科技 #深度学习 #自然语言处理 #神经网络 #hadoop #hbase #hive #zookeeper #spark #kafka #flink #docker #华为云 #部署上线 #动静分离 #Nginx #新人首发 #fastapi #html #css #tcp/ip #网络 #qt #C++ #harmonyos #鸿蒙PC #物联网 #websocket #github #git #大数据 #职场和发展 #程序员创富 #进程控制 #经验分享 #安卓 #gemini #gemini国内访问 #gemini api #gemini中转搭建 #Cloudflare #PyTorch #模型训练 #星图GPU #kylin #ARM服务器 # GLM-4.6V # 多模态推理 #开源 #arm #低代码 #爬虫 #音视频 #Conda # 私有索引 # 包管理 #unity #c# #游戏引擎 #语言模型 #大模型 #ai #ai大模型 #agent #数信院生信服务器 #Rstudio #生信入门 #生信云服务器 #飞牛nas #fnos #word #umeditor粘贴word #ueditor粘贴word #ueditor复制word #ueditor上传word图片 #内网穿透 #cpolar #ci/cd #jenkins #gitlab #node.js #langchain #数据库 #MobaXterm #ubuntu #ssh #flutter #开发语言 #云原生 #iventoy #VmWare #OpenEuler #儿童书籍 #儿童诗歌 #童话故事 #经典好书 #儿童文学 #好书推荐 #经典文学作品 #Harbor #矩阵 #线性代数 #AI运算 #向量 #vscode #mobaxterm #计算机视觉 #ide #区块链 #测试用例 #生活 #RTP over RTSP #RTP over TCP #RTSP服务器 #RTP #TCP发送RTP #前端 #nginx #后端 #serverless #diskinfo # TensorFlow # 磁盘健康 #c++ #算法 #牛客周赛 #AI编程 #aws #云计算 #centos #svn #自动化 #ansible #分布式 #华为 #sql #AIGC #agi #android #腾讯云 #FTP服务器 #javascript #vue上传解决方案 #vue断点续传 #vue分片上传下载 #vue分块上传下载 #Reactor #http #项目 #高并发 #java-ee #文心一言 #AI智能体 #多个客户端访问 #IO多路复用 #回显服务器 #TCP相关API #缓存 #fabric #postgresql #openHiTLS #TLCP #DTLCP #密码学 #商用密码算法 #PyCharm # 远程调试 # YOLOFuse #php #java #jar #Dell #PowerEdge620 #内存 #硬盘 #RAID5 #windows #flask #企业开发 #ERP #项目实践 #.NET开发 #C#编程 #编程与数学 #iBMC #UltraISO #pytorch #microsoft #鸿蒙 #架构 #安全 #网络协议 #jmeter #功能测试 #软件测试 #自动化测试 #mcu #mysql #信息与通信 #程序人生 #科研 #博士 #pycharm #散列表 #哈希算法 #数据结构 #leetcode #风控模型 #决策盲区 #数学建模 #2026年美赛C题代码 #2026年美赛 #uni-app #小程序 #notepad++ #spring boot #内存治理 #django #es安装 #vue.js #web #webdav #课程设计 #dify #计算机网络 #spring cloud #spring #json #jvm #mmap #nio #蓝桥杯 #golang #redis #个人开发 #驱动开发 #游戏 #mvp #设计模式 #ecmascript #elementui #京东云 #性能优化 #rocketmq #DeepSeek #服务器繁忙 #AI #Ansible # 自动化部署 # VibeThinker #Ubuntu服务器 #硬盘扩容 #命令行操作 #VMware #web安全 #阻塞队列 #生产者消费者模型 #服务器崩坏原因 #数据仓库 #c语言 #LLM #vim #gcc #yum #MCP #MCP服务器 #鸭科夫 #逃离鸭科夫 #鸭科夫联机 #鸭科夫异地联机 #开服 #vllm #Streamlit #Qwen #本地部署 #AI聊天机器人 #prometheus #开源软件 #我的世界 #jetty #Android #Bluedroid #udp #智能手机 #网络安全 #everything #钉钉 #机器人 #阿里云 #AI论文写作工具 #学术论文创作 #论文效率提升 #MBA论文写作 #信息可视化 #claude code #codex #code cli #ccusage #数据集 #单片机 #stm32 #嵌入式硬件 #需求分析 #Ascend #MindIE #scala #测试工具 #压力测试 #adb #rabbitmq #protobuf #ModelEngine #设备驱动 #芯片资料 #网卡 #gpu算力 #大模型学习 #AI大模型 #大模型教程 #大模型入门 #DisM++ # 系统维护 #语音识别 #全能视频处理软件 #视频裁剪工具 #视频合并工具 #视频压缩工具 #视频字幕提取 #视频处理工具 #深度优先 #DFS #Linux #TCP #线程 #线程池 #ffmpeg #企业微信 #生信 #测试流程 #金融项目实战 #P2P #webrtc #chatgpt #DS随心转 #java大文件上传 #java大文件秒传 #java大文件上传下载 #java文件传输解决方案 #journalctl #mcp #mcp server #AI实战 #流程图 #论文阅读 #论文笔记 #毕业设计 #RAG #全链路优化 #实战教程 #openresty #lua #wordpress #雨云 #LobeChat #vLLM #GPU加速 #Coze工作流 #AI Agent指挥官 #多智能体系统 #VS Code调试配置 #电脑 #vue3 #天地图 #403 Forbidden #天地图403错误 #服务器403问题 #天地图API #部署报错 #SSH Agent Forwarding # PyTorch # 容器化 #SSH反向隧道 # Miniconda # Jupyter远程访问 #grafana #todesk #asp.net大文件上传 #asp.net大文件上传下载 #asp.net大文件上传源码 #ASP.NET断点续传 #asp.net上传文件夹 #ping通服务器 #读不了内网数据库 #bug菌问答团队 #FL Studio #FLStudio #FL Studio2025 #FL Studio2026 #FL Studio25 #FL Studio26 #水果软件 #数码相机 #epoll #高级IO #debian #svm #amdgpu #kfd #ROCm #asp.net #面试 #react.js #超算服务器 #算力 #高性能计算 #仿真分析工作站 #1024程序员节 #claude #LoRA # RTX 3090 # lora-scripts #fiddler #里氏替换原则 #ddos #幼儿园 #园长 #幼教 #opencv #数据挖掘 #googlecloud #arm开发 #sizeof和strlen区别 #sizeof #strlen #计算数据类型字节数 #计算字符串长度 #银河麒麟 #系统升级 #信创 #国产化 #正则 #正则表达式 #Modbus-TCP #azure #iphone #编辑器 #金融 #金融投资Agent #Agent #AI写作 #ida #研发管理 #禅道 #禅道云端部署 #中间件 #机器学习 #程序员 #守护进程 #复用 #screen #流量监控 #n8n #架构师 #系统架构 #软考 #系统架构师 #STUN # TURN # NAT穿透 #RAID #RAID技术 #磁盘 #存储 #MC #几何学 #拓扑学 #链表 #链表的销毁 #链表的排序 #链表倒置 #判断链表是否有环 #unity3d #服务器框架 #Fantasy #elasticsearch #智能路由器 #transformer #酒店客房管理系统 #毕设 #论文 #凤希AI伴侣 #智慧校园解决方案 #智慧校园一体化平台 #智慧校园选型 #智慧校园采购 #智慧校园软件 #智慧校园专项资金 #智慧校园定制开发 #CFD #Spring AI #STDIO协议 #Streamable-HTTP #McpTool注解 #服务器能力 #时序数据库 #我的世界服务器搭建 #minecraft #paddleocr #pencil #pencil.dev #设计 #HeyGem # 远程访问 # 服务器IP配置 #边缘计算 #simulink #matlab #MS #Materials #sqlite #Playbook #AI服务器 #Triton # CUDA #wsl #L2C #勒让德到切比雪夫 #selenium #SSH保活 #Miniconda #远程开发 #AB包 #海外服务器安装宝塔面板 #负载均衡 #openlayers #bmap #tile #server #vue #autosar #vuejs #eBPF #SSH # ProxyJump # 跳板机 #简单数论 #埃氏筛法 #openEuler #Hadoop #客户端 #嵌入式 #DIY机器人工房 #tensorflow #nacos #银河麒麟aarch64 #uvicorn #uvloop #asgi #event #.net #homelab #Lattepanda #Jellyfin #Plex #Emby #Kodi #推荐算法 #log #TensorRT # Triton # 推理优化 #操作系统 #apache #zabbix #信令服务器 #Janus #MediaSoup #Jetty # CosyVoice3 # 嵌入式服务器 #YOLO #建筑缺陷 #红外 #SMTP # 内容安全 # Qwen3Guard #X11转发 #智能一卡通 #门禁一卡通 #梯控一卡通 #电梯一卡通 #消费一卡通 #一卡通 #考勤一卡通 #进程 #AI产品经理 #大模型开发 #sqlserver #改行学it #创业创新 #北京百思可瑞教育 #百思可瑞教育 #北京百思教育 #求职招聘 #机器视觉 #6D位姿 #risc-v #大语言模型 #长文本处理 #GLM-4 #Triton推理 #tdengine #制造 #涛思数据 #重构 #ms-swift # 一锤定音 # 大模型微调 #deepseek #SSH公钥认证 # 安全加固 #cpp #PowerBI #企业 #数模美赛 #nas #Qwen3-14B # 大模型部署 # 私有化AI #ui #分类 #vp9 #ssm #bash #状态模式 #screen 命令 #macos #远程桌面 #远程控制 #若依 #quartz #框架 #fpga开发 #LVDS #高速ADC #DDR # GLM-TTS # 数据安全 #银河麒麟操作系统 #openssh #华为交换机 #信创终端 #ssl #支付 #振镜 #振镜焊接 #流量运营 #用户运营 #迁移重构 #数据安全 #漏洞 #代码迁移 #llama #ceph #oracle #模版 #函数 #类 #笔试 #目标检测 #蓝耘智算 #版本控制 #Git入门 #开发工具 #代码托管 #搜索引擎 #esp32教程 #双指针 #个人博客 #WEB #C语言 #ONLYOFFICE #MCP 服务器 #laravel #tomcat #shell #CPU利用率 #前端框架 #嵌入式编译 #ccache #distcc #Canal #cursor #数组 #信号处理 #目标跟踪 #流媒体 #NAS #飞牛NAS #监控 #NVR #EasyNVR #spine #进程创建与终止 #ESXi #ollama #llm #Shiro #反序列化漏洞 #CVE-2016-4437 #tcpdump #embedding #运营 #visual studio code #RustDesk #IndexTTS 2.0 #本地化部署 #SA-PEKS # 关键词猜测攻击 # 盲签名 # 限速机制 #树莓派4b安装系统 #产品经理 #团队开发 #墨刀 #figma #车辆排放 #pdf #LangGraph #模型上下文协议 #MultiServerMCPC #load_mcp_tools #load_mcp_prompt #策略模式 #CLI #Python #JavaScript #langgraph.json #CMake #Make #C/C++ #typescript #npm #vps #Anything-LLM #IDC服务器 #私有化部署 #raid #raid阵列 # 高并发部署 #硬件工程 #国产PLM #瑞华丽PLM #瑞华丽 #PLM #结构与算法 #VoxCPM-1.5-TTS # 云端GPU # PyCharm宕机 #webpack #intellij-idea #database #idea #Windows 更新 #学术写作辅助 #论文创作效率提升 #AI写论文实测 #p2p #电气工程 #C# #PLC #YOLOFuse # 水冷服务器 # 风冷服务器 #910B #rdp #扩展屏应用开发 #android runtime #能源 #TLS协议 #HTTPS #漏洞修复 #运维安全 #翻译 #开源工具 #maven #ComfyUI # 推理服务器 # IndexTTS 2.0 # 远程运维 #libosinfo #Dify #ARM架构 #鲲鹏 #微信小程序 #考研 #软件工程 #产品运营 #联机教程 #局域网联机 #局域网联机教程 #局域网游戏 #模拟退火算法 #集成测试 #微服务 #虚拟机 #性能 #优化 #RAM #mongodb #windows11 #系统修复 #select #yolov12 #研究生life #文件传输 #电脑文件传输 #电脑传输文件 #电脑怎么传输文件到另一台电脑 #电脑传输文件到另一台电脑 #说话人验证 #声纹识别 #CAM++ #其他 #PTP_1588 #gPTP #cnn #RXT4090显卡 #RTX4090 #深度学习服务器 #硬件选型 #gitea #浏览器自动化 #python #群晖 #音乐 #IntelliJ IDEA #Spring Boot #neo4j #NoSQL #SQL #Windows #数据分析 #SSH免密登录 #万悟 #联通元景 #智能体 #镜像 #结构体 #TCP服务器 #开发实战 #OBC #idm #网站 #截图工具 #批量处理图片 #图片格式转换 #图片裁剪 #零售 #log4j #健身房预约系统 #健身房管理系统 #健身管理系统 #上下文工程 #langgraph #意图识别 #Android16 #音频性能实战 #音频进阶 #代理 #ESP32 #传感器 #MicroPython #3d #5G #平板 #交通物流 #智能硬件 #RK3576 #瑞芯微 #硬件设计 #CTF #gateway #Comate #SSE # AI翻译机 # 实时翻译 #数据采集 #浏览器指纹 #clickhouse #arm64 #jupyter #无人机 #Deepoc #具身模型 #开发板 #未来 #edge #迭代器模式 #观察者模式 #twitter #scrapy #r-tree #聊天小程序 #eclipse #servlet #UOS #海光K100 #统信 #NFC #智能公交 #服务器计费 #FP-增长 #CANN #wpf #串口服务器 #Modbus #MOXA #mybatis #Proxmox VE #虚拟化 #硬件 #Fun-ASR # 语音识别 # WebUI #CUDA #交互 #UDP套接字编程 #UDP协议 #网络测试 #部署 #GPU服务器 #8U #硬件架构 #昇腾300I DUO #NPU #lvs #intellij idea #Host #渗透测试 #SSRF #音乐分类 #音频分析 #ViT模型 #Gradio应用 #鼠大侠网络验证系统源码 #whisper #cosmic #vnstat #c++20 #游戏私服 #云服务器 #AutoDL #H5 #跨域 #发布上线后跨域报错 #请求接口跨域问题解决 #跨域请求代理配置 #request浏览器跨域 #运维开发 #opc ua #opc #anaconda #虚拟环境 #SSH跳板机 # Python3.11 #LabVIEW知识 #LabVIEW程序 #LabVIEW功能 #labview #东方仙盟 #游戏机 #JumpServer #堡垒机 #API限流 # 频率限制 # 令牌桶算法 #UDP的API使用 #处理器 #黑群晖 #无U盘 #纯小白 #指针 #Fluentd #Sonic #日志采集 #Gunicorn #WSGI #Flask #并发模型 #容器化 #性能调优 #teamviewer #蓝湖 #Axure原型发布 # REST API # GLM-4.6V-Flash-WEB #ip #ambari #单元测试 #Socket网络编程 #turn #黑客技术 #网安应急响应 #计算机 # 目标检测 #ai编程 #restful #ajax #微PE # GLM # 服务连通性 #视频去字幕 #flume #muduo库 #零代码平台 #AI开发 #UDP #uv #uvx #uv pip #npx #Ruff #pytest #数据恢复 #视频恢复 #视频修复 #RAID5恢复 #流媒体服务器恢复 #框架搭建 #聚类 #SRS #直播 #OPCUA #环境搭建 #milvus #springboot #知识库 #pandas #matplotlib #昇腾 #web server #请求处理流程 #chrome #RSO #机器人操作系统 #glibc #Anaconda配置云虚拟环境 #OSS #firefox #MQTT协议 #vivado license #CVE-2025-68143 #CVE-2025-68144 #CVE-2025-68145 #安恒明御堡垒机 #windterm #rust #html5 #政务 #集成学习 #https # 硬件配置 #算力一体机 #ai算力服务器 #可信计算技术 #winscp #青少年编程 #自动驾驶 # 双因素认证 #powerbi #Clawdbot #个人助理 #数字员工 #SMP(软件制作平台) #EOM(企业经营模型) #应用系统 #tornado #rustdesk #项目申报系统 #项目申报管理 #项目申报 #企业项目申报 #连接数据库报错 #JAVA #Java #Docker # Base64编码 # 多模态检测 #IPv6 #DNS #reactjs #web3 #源码 #闲置物品交易系统 #系统安全 #ipmitool #BMC #C #bootstrap #SPA #单页应用 #web3.py #人脸识别 #人脸核身 #活体检测 #身份认证与人脸对比 #微信公众号 #swagger #IndexTTS2 # 阿里云安骑士 # 木马查杀 #1panel #vmware #prompt #贪心算法 #YOLOv8 # Docker镜像 #麒麟OS #mariadb #学习笔记 #jdk #汇编 #mamba #企业级存储 #网络设备 #iot #多模态 #微调 #超参 #LLamafactory #土地承包延包 #领码SPARK #aPaaS+iPaaS #数字化转型 #智能审核 #档案数字化 #农产品物流管理 #物流管理系统 #农产品物流系统 #农产品物流 #Smokeping #xss #pve #paddlepaddle #zotero #WebDAV #同步失败 #代理模式 #工具集 #大模型应用 #API调用 #PyInstaller打包运行 #服务端部署 #ShaderGraph #图形 #VSCode # SSH #VMware Workstation16 #服务器操作系统 #排序算法 #排序 #Linux多线程 #欧拉 #CSDN #aiohttp #asyncio #异步 #Langchain-Chatchat # 国产化服务器 # 信创 #软件 #本地生活 #电商系统 #商城 #2026AI元年 #年度趋势 #markdown #建站 #儿童AI #图像生成 #pjsip #游戏美术 #技术美术 #游戏策划 #游戏程序 #用户体验 # 模型微调 #区间dp #二进制枚举 #图论 #麒麟 #.netcore #多线程 #性能调优策略 #双锁实现细节 #动态分配节点内存 # 自动化运维 #实体经济 #商业模式 #软件开发 #数智红包 #商业变革 #创业干货 #HBA卡 #RAID卡 #AI生成 # outputs目录 # 自动化 #ue5 #大学生 #大作业 #ZooKeeper #ZooKeeper面试题 #面试宝典 #深入解析 #大模型部署 #mindie #大模型推理 #业界资讯 #n8n解惑 #Go并发 #高并发架构 #Goroutine #系统设计 #Tracker 服务器 #响应最快 #torrent 下载 #2026年 #Aria2 可用 #迅雷可用 #BT工具通用 #net core #kestrel #web-server #asp.net-core #elk #插入排序 #esp32 arduino #Zabbix #CosyVoice3 #语音合成 #HistoryServer #Spark #YARN #jobhistory #FASTMCP #Chat平台 #TFTP #NSP #下一状态预测 #aigc #内存接口 # 澜起科技 # 服务器主板 #性能测试 #LoadRunner # 显卡驱动备份 #测试覆盖率 #可用性测试 #EMC存储 #存储维护 #NetApp存储 #kmeans #广播 #组播 #并发服务器 #x86_64 #数字人系统 #数字孪生 #三维可视化 #工厂模式 #智慧城市 #海外短剧 #海外短剧app开发 #海外短剧系统开发 #短剧APP #短剧APP开发 #短剧系统开发 #海外短剧项目 #eureka #随机森林 #经济学 #rtsp #转发 #编程 #c++高并发 #百万并发 #Termux #Samba #SSH别名 #WinDbg #Windows调试 #内存转储分析 #企业存储 #RustFS #对象存储 #高可用 #三维 #3D #三维重建 #asp.net上传大文件 #信创国产化 #达梦数据库 #AI+ #coze #AI入门 #AI赋能 #CVE-2025-61686 #路径遍历高危漏洞 #计组 #数电 #Node.js #漏洞检测 #CVE-2025-27210 #导航网 #Llama-Factory # 大模型推理 #uip #PyTorch 特性 #动态计算图 #张量(Tensor) #自动求导Autograd #GPU 加速 #生态系统与社区支持 #与其他框架的对比 #cascadeur #设计师 #AI视频创作系统 #AI视频创作 #AI创作系统 #AI视频生成 #AI工具 #文生视频 #AI创作工具 #进程等待 #wait #waitpid # 服务器IP # 端口7860 #全文检索 # 代理转发 #echarts #GPU ##租显卡 #Xshell #Finalshell #生物信息学 #组学 # GPU租赁 # 自建服务器 #统信UOS #win10 #qemu #VibeVoice # 语音合成 # 云服务器 #web服务器 #ThingsBoard MCP #可撤销IBE #服务器辅助 #私钥更新 #安全性证明 #双线性Diffie-Hellman # 公钥认证 #H5网页 #网页白屏 #H5页面空白 #资源加载问题 #打包部署后网页打不开 #HBuilderX #A2A #GenAI #HarmonyOS #遛狗 #VMWare Tool #ngrok #MinIO服务器启动与配置详解 #视觉检测 #visual studio #心理健康服务平台 #心理健康系统 #心理服务平台 #心理健康小程序 #SSH复用 # 远程开发 #Nacos #gRPC #注册中心 #Rust #Tokio #异步编程 #系统编程 #Pin #http服务器 #win11 #磁盘配额 #存储管理 #文件服务器 #形考作业 #国家开放大学 #系统运维 #自动化运维 #插件 #机器人学习 #DHCP #C++ UA Server #SDK #跨平台开发 # IP配置 # 0.0.0.0 #智能家居 #注入漏洞 #nvidia #galeweather.cn #高精度天气预报数据 #光伏功率预测 #风电功率预测 #高精度气象 #GATT服务器 #蓝牙低功耗 #线性回归 #DAG #c #服务器解析漏洞 #勒索病毒 #勒索软件 #加密算法 #.bixi勒索病毒 #数据加密 # ControlMaster #实时音视频 #safari #贴图 #材质 #JT/T808 #车联网 #车载终端 #模拟器 #仿真器 #开发测试 #memory mcp #Cursor #网路编程 #mapreduce #论文复现 #知识 #Buck #NVIDIA #交错并联 #DGX #hibernate #AI赋能盾构隧道巡检 #开启基建安全新篇章 #以注意力为核心 #YOLOv12 #AI隧道盾构场景 #盾构管壁缺陷病害异常检测预警 #隧道病害缺陷检测 #openclaw #IFix # 远程连接 #memcache #大剑师 #nodejs面试题 #AI技术 #C2000 #TI #实时控制MCU #AI服务器电源 #攻防演练 #Java web #红队 # 树莓派 # ARM架构 #AITechLab #cpp-python #CUDA版本 #ranger #MySQL8.0 #连锁药店 #连锁店 #GB28181 #SIP信令 #SpringBoot #视频监控 #WT-2026-0001 #QVD-2026-4572 #smartermail #TTS私有化 # IndexTTS # 音色克隆 #ARM64 # DDColor # ComfyUI #Ubuntu #ESP32编译服务器 #Ping #DNS域名解析 #YOLO26 #YOLO11 #screen命令 #分布式数据库 #集中式数据库 #业务需求 #选型误 # Connection refused #面向对象 #智能体来了 #智能体对传统行业冲击 #行业转型 #系统管理 #服务 #abtest # keep-alive # ARM服务器 #源代码管理 #管道Pipe #system V #chat #Claude #clamav #CogVideoX #AI部署 #SAP #ebs #metaerp #oracle ebs # 高并发 #appche #命令模式 #dubbo #muduo #TcpServer #accept #高并发服务器 #AI-native #dba #LangFlow # 轻量化镜像 # 边缘计算 #国产化OS #图像处理 #yolo #SSH跳转 #go #postman # GPU集群 #高品质会员管理系统 #收银系统 #同城配送 #最好用的电商系统 #最好用的系统 #推荐的前十系统 #JAVA PHP 小程序 #WinSCP 下载安装教程 #SFTP #FTP工具 #服务器文件传输 #excel #计算几何 #斜率 #方向归一化 #叉积 #samba #copilot # 批量管理 #ASR #SenseVoice #硬盘克隆 #DiskGenius #媒体 #ipv6 #duckdb #weston #x11 #x11显示服务器 #逻辑回归 #手机h5网页浏览器 #安卓app #苹果ios APP #手机电脑开启摄像头并排查 #语音生成 #TTS #cesium #可视化 #IO #证书 #ArkUI #ArkTS #鸿蒙开发 # 数字人系统 # 远程部署 ##程序员和算法的浪漫 #JNI #CPU #测评 #CCE #Dify-LLM #Flexus #puppeteer #KMS #slmgr #宝塔面板部署RustDesk #RustDesk远程控制手机 #手机远程控制 #长文本理解 #glm-4 #推理部署 #TRO #TRO侵权 #TRO和解 #运维工具 #Aluminium #Google #社科数据 #数据统计 #经管数据 #POC #问答 #交付 #动态规划 #xlwings #Excel #Discord机器人 #云部署 #程序那些事 #服务器IO模型 #非阻塞轮询模型 #多任务并发模型 #异步信号模型 #多路复用模型 # 黑屏模式 # TTS服务器 #前端开发 #领域驱动 #自由表达演说平台 #演说 #移动端h5网页 #调用浏览器摄像头并拍照 #开启摄像头权限 #拍照后查看与上传服务器端 #摄像头黑屏打不开问题 #nfs #iscsi #因果学习 #kong #Kong Audio #Kong Audio3 #KongAudio3 #空音3 #空音 #中国民乐 #范式 #React安全 #漏洞分析 #Next.js #RAGFlow #DeepSeek-R1 #Karalon #AI Test #文件IO #输入输出流 #文件管理 #国产开源制品管理工具 #Hadess #一文上手 # 大模型 # 模型训练 #scanf #printf #getchar #putchar #cin #cout #ET模式 #非阻塞 #ICPC #递归 #线性dp #工程实践 #webgl #租显卡 #训练推理 #就业 #支持向量机 #图像识别 #多进程 #python技巧 #VPS #搭建 #文本生成 #CPU推理 #轻量化 #低配服务器 #国产操作系统 #V11 #kylinos #KMS激活 #gpt #API #音诺ai翻译机 #AI翻译机 # Ampere Altra Max #wps #sklearn #Java程序员 #Java面试 #后端开发 #Spring源码 #Spring #numpy #poll #人形机器人 #人机交互 #xml #Syslog #系统日志 #日志分析 #日志监控 #Autodl私有云 #深度服务器配置 #统信操作系统 #域名注册 #新媒体运营 #网站建设 #国外域名 #人脸识别sdk #视频编解码 #DDD #tdd #挖漏洞 #攻击溯源 #easyui #stl #IIS Crypto #blender #warp #门禁 #梯控 #智能梯控 #电梯 #电梯运力 #电梯门禁 #bond #服务器链路聚合 #网卡绑定 #编程助手 # GPU服务器 # tmux #程序开发 #程序设计 #计算机毕业设计 #idc #Prometheus #题解 #图 #dijkstra #迪杰斯特拉 #高斯溅射 #智能制造 #供应链管理 #工业工程 #库存管理 #Puppet # IndexTTS2 # TTS #量子计算 #程序定制 #毕设代做 #课设 #交换机 #三层交换机 #个人电脑 #KMS 激活 #RK3588 #RK3588J #评估板 #核心板 #嵌入式开发 #AI智能棋盘 #Rock Pi S #MC群组服务器 # Qwen3Guard-Gen-8B #树莓派 #N8N #云开发 #gpu #nvcc #cuda #Cpolar #国庆假期 #服务器告警 #漏洞挖掘 #unix #CS2 #debian13 #BoringSSL #Moltbook # 鲲鹏 #SQL注入主机 #http头信息 #resnet50 #分类识别训练 #Coturn #TURN #k8s #OpenManage #模块 # 权限修复 #ICE #Spire.Office #隐私合规 #网络安全保险 #法律风险 #风险管理 #温湿度监控 #WhatsApp通知 #IoT #MySQL #React #Next #CVE-2025-55182 #RSC # HiChatBox # 离线AI #SMARC #ARM #空间计算 #原型模式 #nosql #devops #戴尔服务器 #戴尔730 #装系统 #junit #汽车 #文件上传漏洞 #静脉曲张 #腿部健康 #Kylin-Server #服务器安装 #远程访问 #远程办公 #飞网 #安全高效 #配置简单 #快递盒检测检测系统 #短剧 #短剧小程序 #短剧系统 #微剧 # 智能运维 # 性能瓶颈分析 #FaceFusion # Token调度 # 显存优化 #WRF #WRFDA #数据访问 #vncdotool #链接VNC服务器 #如何隐藏光标 # 服务器IP访问 # 端口映射 #公共MQTT服务器 #bug #网络配置实战 #Web/FTP 服务访问 #计算机网络实验 #外网访问内网服务器 #Cisco 路由器配置 #静态端口映射 #网络运维 #RPA #影刀RPA #AI办公 #CNAS #CMA #程序文件 #wireshark #网络安全大赛 #FHSS # DIY主机 # 交叉编译 #路由器 #outlook #错误代码2603 #无网络连接 #2603 #mssql #算力建设 #跳槽 #视觉理解 #Moondream2 #多模态AI #lucene #nodejs #云服务器选购 #Saas #具身智能 #CA证书 #SSH密钥 #练习 #基础练习 #循环 #九九乘法表 #计算机实现 #dynadot #域名 #ETL管道 #向量存储 #数据预处理 #DocumentReader #HarmonyOS APP #esb接口 #走处理类报异常 #CS336 #Assignment #Experiments #TinyStories #Ablation #密码 #b树 #le audio #蓝牙 #低功耗音频 #通信 #连接 #星际航行 #agentic bi #smtp #smtp服务器 #PHP #银河麒麟部署 #银河麒麟部署文档 #银河麒麟linux #银河麒麟linux部署教程 #声源定位 #MUSIC #windbg分析蓝屏教程 #Keycloak #Quarkus #AI编程需求分析 #ROS #ARMv8 #内存模型 #内存屏障 #fs7TF #娱乐 #敏捷流程 #AI 推理 #NV #npu #ServBay #canvas层级太高 #canvas遮挡问题 #盖住其他元素 #苹果ios手机 #安卓手机 #调整画布层级 #学术生涯规划 #CCF目录 #基金申请 #职称评定 #论文发表 #科研评价 #顶会顶刊 #安全架构 #远程软件 #分子动力学 #化工仿真 #SEO优化 # OTA升级 # 黄山派 #内网 #ansys #ansys问题解决办法 #节日 #Kuikly #openharmony # 网络延迟 #基础语法 #标识符 #常量与变量 #数据类型 #运算符与表达式 #地理 #遥感 #视频 #taro #代理服务器 #主板 #总体设计 #电源树 #框图 #工作 #超时设置 #客户端/服务器 #网络编程 #挖矿 #Linux病毒 #sql注入 #Archcraft #Linly-Talker # 数字人 # 服务器稳定性 #雨云服务器 #Minecraft服务器 #教程 #MCSM面板 #Apple AI #Apple 人工智能 #FoundationModel #Summarize #SwiftUI #实在Agent # 服务器配置 # GPU #传统行业 #Gateway #认证服务器集成详解 #glances #服务器开启 TLS v1.2 #IISCrypto 使用教程 #TLS 协议配置 #IIS 安全设置 #服务器运维工具 #ftp #sftp #uniapp #合法域名校验出错 #服务器域名配置不生效 #request域名配置 #已经配置好了但还是报错 #uniapp微信小程序 #电子电气架构 #系统工程与系统架构的内涵 #Routine #华为od #华为机试 #react native #gnu # 批量部署 # 键鼠锁定 #mtgsig #美团医药 #美团医药mtgsig #美团医药mtgsig1.2 #opc模拟服务器 #远程连接 #百度 #ueditor导入word #cpu #工程设计 #预混 #扩散 #燃烧知识 #层流 #湍流 #报表制作 #职场 #数据可视化 #用数据讲故事 # WebRTC #后端框架 #服务器线程 # SSL通信 # 动态结构体 #RWK35xx #语音流 #实时传输 #node #参数估计 #矩估计 #概率论 #寄存器 #MCP服务器注解 #异步支持 #方法筛选 #声明式编程 #自动筛选机制 #LE Audio #BAP #composer #symfony #java-zookeeper #coffeescript #pxe #ue4 #DedicatedServer #独立服务器 #专用服务器 # child_process #H3C #sentinel #AI大模型应用开发 #可再生能源 #绿色算力 #风电 #麦克风权限 #访问麦克风并录制音频 #麦克风录制音频后在线播放 #用户拒绝访问麦克风权限怎么办 #uniapp 安卓 苹果ios #将音频保存本地或上传服务器 #仙盟创梦IDE #GLM-4.6V-Flash-WEB # AI视觉 # 本地部署 #语义搜索 #嵌入模型 #Qwen3 #AI推理 #网络攻击模型 #pyqt #AI应用编程 #dlms #dlms协议 #逻辑设备 #逻辑设置间权限 #r语言 #scikit-learn #个性化推荐 #BERT模型 #安全威胁分析 #Minecraft #PaperMC #我的世界服务器 #tcp/ip #网络 #EN4FE #STDIO传输 #SSE传输 #WebMVC #WebFlux #电商 #工业级串口服务器 #串口转以太网 #串口设备联网通讯模块 #串口服务器选型 #入侵 #日志排查 #小艺 #搜索 #高仿永硕E盘的个人网盘系统源码 #Spring AOP #人大金仓 #Kingbase #高精度农业气象 #Ward #AI应用 #思爱普 #SAP S/4HANA #ABAP #NetWeaver #高考 #claude-code #WAN2.2 #Beidou #北斗 #SSR #4U8卡 AI 服务器 ##AI 服务器选型指南 #GPU 互联 #GPU算力 #日志模块 #bigtop #hdp #hue #kerberos #dash #docker安装seata #信息安全 #信息收集 #生产服务器问题查询 #日志过滤 # AI部署 #材料工程 #智能电视 #VMware创建虚拟机 #远程更新 #缓存更新 #多指令适配 #物料关联计划 #防毒面罩 #防尘面罩 #数据报系统 #m3u8 #HLS #移动端H5网页 #APP安卓苹果ios #监控画面 直播视频流 #决策树 #DooTask #sglang #效率神器 #办公技巧 #自动化工具 #Windows技巧 #打工人必备 #UEFI #BIOS #Legacy BIOS #Socket # 服务器迁移 # 回滚方案 #旅游 #开关电源 #热敏电阻 #PTC热敏电阻 #身体实验室 #健康认知重构 #系统思维 #微行动 #NEAT效应 #亚健康自救 #ICT人 #西门子 #汇川 #Blazor #dreamweaver #晶振 #云计算运维 #运维 #夏天云 #夏天云数据 #hdfs #华为od机试 #华为od机考 #华为od最新上机考试题库 #华为OD题库 #华为OD机试双机位C卷 #od机考题库 #银河麒麟服务器系统 #Python3.11 #clawdbot #AI工具集成 #容器化部署 #分布式架构 #Matrox MIL #二次开发 #I/O模型 #并发 #水平触发、边缘触发 #多路复用 #vertx #vert.x #vertx4 #runOnContext #CMC #防火墙 #0day漏洞 #DDoS攻击 #漏洞排查 #单例模式 #懒汉式 #恶汉式 #实时检测 #卷积神经网络 #基金 #股票 #AI电商客服 #余行补位 #意义对谈 #余行论 #领导者定义计划 #spring ai #oauth2 #nmodbus4类库使用教程 #docker-compose #rtmp #AE # 局域网访问 # 批量处理 #rag # 高温监控 #ossinsight #cocos2d #图形渲染 # 环境迁移 #测速 #iperf #iperf3 #gerrit #小智 #xshell #host key #期刊 #SCI #rsync # 数据同步 #游戏服务器断线 #claudeCode #content7 #odoo #外卖配送 #语义检索 #向量嵌入 #boltbot #榛樿鍒嗙被 # 串口服务器 # NPort5630 #YOLO识别 #YOLO环境搭建Windows #YOLO环境搭建Ubuntu #OpenHarmony #Python办公自动化 #Python办公 #人脸活体检测 #live-pusher #动作引导 #张嘴眨眼摇头 #苹果ios安卓完美兼容 #强化学习 #策略梯度 #REINFORCE #蒙特卡洛 #L6 #L10 #L9 #套接字 #I/O多路复用 #字节序 #反向代理 #阿里云RDS # ms-swift #PN 结 #超算中心 #PBS #lsf #adobe #数据迁移 #vrrp #脑裂 #keepalived主备 #高可用主备都持有VIP #软件需求 #express #cherry studio #gmssh #宝塔 #Exchange #free #vmstat #sar #系统安装 #铁路桥梁 #DIC技术 #箱梁试验 #裂纹监测 #四点弯曲 #MinIO #Qwen3-VL # 服务状态监控 # 视觉语言模型 #AI Agent #开发者工具 #okhttp #计算机外设 #职场发展 #边缘AI # Kontron # SMARC-sAMX8 #隐函数 #常微分方程 #偏微分方程 #线性微分方程 #线性方程组 #非线性方程组 #复变函数 #健康医疗 #UDP服务器 #recvfrom函数 #remote-ssh #OpenAI #故障 #Arduino BLDC #核辐射区域探测机器人 #二值化 #Canny边缘检测 #轮廓检测 #透视变换 #esp32 #mosquito #2025年 #FRP #AI教程 #自动化巡检 #istio #服务发现 #jquery #fork函数 #进程创建 #进程终止 #moltbot #session #JADX-AI 插件 #starrocks #运动 #tekton #Tetrazine-Acid #1380500-92-4 #新浪微博 #传媒 #DuckDB #协议