最新资讯

  • 【LINUX网络】HTTP协议基本结构、搭建自己的HTTP简单服务器

【LINUX网络】HTTP协议基本结构、搭建自己的HTTP简单服务器

2026-02-01 21:27:29 栏目:最新资讯 2 阅读

目录

1. 初识HTTP

2. URL

        2.1 基本结构

2.2 URL中的?与urldecodeurlencode

易混淆:URL和HTTP传输请求两者是什么关系?

HTTP的宏观结构

3. DEMO CODE

loop模块,核心逻辑

HttpServer

初代版本(DEMO 0.0)

DEMO 1.0

DEMO 2.0

tips:简单介绍一下wwwroot以及index.html

示例

文件结构

DEMO 3.0

家目录wwwroot

class Response

Build--------------Response不可缺少的一环

index.html作为默认访问是需要特殊处理的


        书接上回,虽说应用层在一定意义上是可以被我们自己实现的,但其实应用层依然有很多行业规范。其中最出名的当然属HTTP

        

【LINUX网络】应用层自定义协议与序列化——通过实现一个简单的网络计算器来体会自定义协议-CSDN博客

1. 初识HTTP

        HyperText Transfer,超文本传输协议,是一种规定了客户端如何访问服务器的协议,以保证超文本可以被交换和传输(如 HTML 文档)

         客户端通过 HTTP 协议向服务器发送 请求,服务器收到请求后处理并返回响应。

        Http有以下的一些特点:

       

        无连接、无状态,即服务器不会保存客户端的信息,每次访问都需要重新建立连接。比如,在OAuth2协议中,Token需要一直被放在URL中表示具有访问权限。

http是基于Tcp实现的:

应用层协议:HTTP

HTTP基于TCP协议实现

采用TCP意味着继承了其全双工通信、序列化传输和报文交换等特性

不同应用层协议有各自独特的需求,因此协议种类繁多

但所有应用层协议都存在一个共同点:依赖流式服务确保报文的完整性

tips:网络中的一些新名词(AI生成):

        

超文本(Hypertext)

超文本是一种文本形式,它包含可以链接到其他文本的超链接。这些链接可以是文本、图片、视频等其他媒体形式。超链接使得用户可以通过点击来跳转到同一文档的不同部分或完全不同的文档。超文本是万维网(World Wide Web)的基础,它允许用户在不同网页之间导航。

HTML(HyperText Markup Language)

HTML 是一种标记语言,用于创建网页和网页应用程序中的内容结构。它定义了网页的结构和内容,但不涉及样式和行为。HTML 文档由一系列的元素(elements)组成,这些元素通过标签(tags)来定义。例如, 定义了整个网页的开始和结束, 定义了网页的主体内容,

定义了不同级别的标题,

定义了段落。

HTML 5 是 HTML 的最新版本,它增加了对多媒体内容的支持,如音频和视频,以及图形和动画等。

XML(eXtensible Markup Language)

XML 是一种标记语言,用于存储和传输数据。它与 HTML 相似,但 XML 被设计为一种数据描述语言,而不是一种用于显示数据的语言。XML 允许用户定义自己的标签,这使得它非常灵活,可以用于各种不同的数据表示需求。

XML 的一些关键特性包括:

  • 可扩展性:用户可以定义自己的标签来描述数据。

  • 自描述性:XML 文档包含了足够的信息来描述其内容,不需要外部的元数据。

  • 层级结构:XML 数据可以组织成树状结构,这使得它非常适合表示复杂的数据关系

正式学习http是什么之前,再来了解一下什么是URL

2. URL

        2.1 基本结构

平时我们俗称的 " 网址 " 其实就是说的 URL

URL还有另一个名字:Uniform Resource Locator,简称 URL)是互联网上用来标识某一处资源的地址。URL 提供了一种方式,通过它可以访问互联网上的各种资源,如网页、图片、视频、音频文件等。

对于一个URL,首先是协议名称(https表示是加密状态)

                        

然后的news.qq.com是域名。域名(Domain Name)是互联网上用于标识和定位计算机或计算机组(通常是指网站)的一个文本字符串。域名系统(Domain Name System,简称DNS)将域名转换为数字IP地址,这样人们就可以通过易于记忆的域名来访问网站,而不必记住复杂的数字地址。由以上内容不难看出,其实域名是IP地址的另一种表现形式,会被体系结构解释成目标服务器的IP地址。

最后的rain/a/xxxxxx是路劲,其实是目标文件在服务器上的被访问资源的地址(有没有觉得这个地址看着很像是文件地址?)。被访问的资源就是一种文件。

        在URL(统一资源定位符)中,以斜杠 / 开始的部分(比如上述图片中的就是/rain/...)并不总是代表文件系统的根目录,而是通常被称为“web根目录”。web根目录是Web服务器上一个特定的目录,它通常是Web服务器提供服务的起始点,所有的Web内容都是从这个目录开始组织的。

所以,HTTP请求的资源本质是文件。

什么是上网

对于我们程序员来说,用户上网的一些基础背景概念:

1.我的数据给别人。别人的数据给我 -> IO->上网的所有行为,都是在IO

2. 什么是资源?图片、音频、视频、文本

3. 客户访问的资源一定是在世界上的某台机器上放着的(通过IP确定)。并且为了获取资源,需要确定系统的路径->这两个信息被URL合在一起确定下来了。

现在,假设我们已经通过URL打开了一个资源。刚刚说到,http是不记录访问者信息的,请问如何把资源推送回去呢?

 打开文件之后,用哪个端口号推回去呢?如何把资源送回去呢?

因为指明协议,就相当于明确了回来的时候是要回到哪个端口(比如1024以内的端口,都被比较出名的协议给占了)

这也是为什么URL中只标注了域名,没有标注端口号      

        成熟的应用层协议通常与特定的端口号强烈关联。这种关联是通过互联网号码分配机构(IANA,Internet Assigned Numbers Authority)来管理和分配的,以确保不同服务和应用程序之间的通信不会发生冲突。

        换句话说,像http这样的协议,端口号都是写死了的。

一些知名端口(Well-Known Ports):从0到1023,这些端口号被IANA分配给了特定的服务。例如:

  • 端口 80 通常用于 HTTP(超文本传输协议)。

  • 端口 443 通常用于 HTTPS(安全的超文本传输协议)。

  • 端口 22 通常用于 SSH(安全外壳协议)。

  • 端口 25 通常用于 SMTP(简单邮件传输协议)

2.2 URL中的?与urldecodeurlencode

?的右边都是资源或者参数

        URL(Uniform Resource Locator,统一资源定位符)的 ? 右边部分被称为查询字符串(query string)。查询字符串用于向服务器提供额外的信息,这些信息通常用于指定对资源的某些操作或过滤条件。查询字符串由一个或多个参数组成,每个参数由一个名称和一个值组成,参数之间用 & 符号分隔。

        比如 搜qinghua,wd参数(world,关键字)值就是qinghua,最后一排还有一个prefixsug,可能是某种前缀,表示还要搜索以qinghua为前缀的其他信息。

urlencode:就像C语言中的/ % 等特殊转义符,在搜索的时候会被加码成其他样子。

包括不限于 : // ? / = &都是被转义了的。

转义的规则如下 :
将需要转码的字符转为 16 进制,然后从右到左,取 4 ( 不足 4 位直接处理 ) ,每 2
做一位,前面加上 % ,编码成 %XY 格式
再比如,搜索这几个转移字符 //?=&/
这是一个可以URL解码编码的工具:
UrlEncode编码/UrlDecode解码 - 站长工具

易混淆:URL和HTTP传输请求两者是什么关系?

先来看一眼,http的请求到底是长什么样的

HTTP是一种用于在网络上传输数据的协议,就像TCP一样,只不过http是基于TCP的协议

URL才是日常所说的”网址“,是用于指定网络上的资源位置,是一个基于万维网的‘‘文件地址’’


关于http协议,是如何做到如何保证面向字节流的完整性的?

HTTP的宏观结构

要想进一步理解HTTP,必须手搓一个,手搓之前,一起看一下宏观结构

        首先是请求行,请求行依次包含三个数据内容:请求方法(最常用的只有GET和POST)、URL、HTTP协议版本,三个内容之间用空格隔开。以下是常见的http方法,具体的使用会在以后详细讲。

        

然后是http的请求报头:

                        

包含多行内容,每一行都有自己固定的格式,也都是以换行符代表结束

Key一般是请求相关的属性,Value一般是该属性的内容,后会接一个空行,空行的本质就是

HTTP RESPONSE同理,状态行内容有相应的变化。

名字上,RESPONSE主要是状态行 响应报头 空行 响应正文

状态码,比如404,描述就是not found

很明显,这样的request或者response是需要被OS管理的

可以分别构造两个class来管理两种属性。请求正文、报头等不过就是里面的成员,甚至还能大胆推测,就是string类的

在把这个类丢进tcp的缓冲区之前,一定需要进行序列化,序列化之后再让TCP去传输,传输也就不需要刻意再去管,交给TCP即可。

                        

现在再看这是不是更能理解为什么HTTP是应用层协议了?

说白了,其本职工作只是结构化、序列化,真正的传输(在当前视角下),只要丢进TCP层次的缓冲区即可。

如果有看过上一文的读者可能会发现,如果HTTP更多的功能是用于序列化,那其实非常像网络计算器中的Parse函数。

大概思考如何进行序列化:

序列化,就是把前面的内容全部缩成一个长字符串

空行可以用作分割,空行之前就是报头,空行之后就是正文

报头里面有描述正文长度的字段

 反序列化的时候就可以按行读取,一定也会读到空行。读到空行之后,一定可以在请求报头中获得一个Content_length字段,再次读正文的时候就比较方便了。

http本身作为一个协议,序列化等都是自己实现的,没有依赖其他的比如JSON库。

REQUEST和RESPONSE很像,所以他们的序列化和反序列化做法可以说是几乎完全一样的。

理论部分暂时结束,下面会基于以前的部分代码先进行一次封装,封装好了就构建HTTP,读者朋友可以先跟着之前的敲一遍,也可以直接跟着以下代码写。【LINUX网络】使用TCP简易通信_liunx 不启用中转连接tcp服务-CSDN博客


3. DEMO CODE

                               -----------------------记录完成demo代码中的过程与遇到的困难

写代码才能真正手撕清楚这个过程,不过这个写和调试的过程注定是费时和痛苦的。

对于初学者来说,代码量确实有点大,共勉。

我的构思中,大概分层为:Socket层(采用模板方法模式,将Socket作为基类,TcpSocket作为派生类,读者可以自行实现UdpServer),TcpServer层(复用Socket层)

先谈套接字封装,封装完了就可以实现一个简单的http_server

1. 封装Socket的模块

TcpServer大概分为socket,bind,listen,accept四步,并不是直接就能用的。我们希望能封装一个类来完成以上工作,让我们可以直接在TcpServer中使用

这次的封装采用   模板方法模式

首先完成一个Socket的类:

注意:

                除了几个到派生类中去具体实现的虚方法,可以先刻画好一个BuildSocket方法,到时候可以直接调。

               根据socketindlistenccept四步依次实现,不过应当考虑到accept是需要在服务器运行的主逻辑中去执行的

#pragma once
#include 
#include 
#include 
// 网络四件套
#include 
#include 
#include 
#include 

// 基类,规定创建socket的方法
// 提供若干个、固定模式的方法
class Socket
{
public:
    virtual ~Socket() = 0;
    virtual int SocketOrDie() = 0;
    virtual bool BindOrDie() = 0;
    virtual bool ListenOrDie() = 0;
    virtual int Accept() = 0;
    virtual void Close();

#ifdef _WIN
    BuildTcpSocket()
    {
        SocketOrDie();
        BindOrDie();
        ListenOrDie();
    }
#else //LINUX版本
    void BuildSocket()
    {
        SocketOrDie();
        BindOrDie();
        ListenOrDie();
    }
#endif

private:
};

 开始实现派生类:private中暂时构思的是加一个_sock_fd即可,初始赋值为-1,检测到值为-1就是暂时还不能使用的。

     virtual int SocketOrDie() override
    {
        _sock_fd = socket(AF_INET,SOCK_STREAM,0);
        if(_sock_fd < 0)
        {
            LOG(LogLevel::ERROR) << "Tcp socket fail";
            DIE(SOCK_ERR);
        }
        LOG(LogLevel::DEBUG)<<"listen socket success";

        return _sock_fd;
    }

Bind的时候要注意结合之前我们自己实现的封装网络地址的类。Bind的时候需要把端口号传进去,

用传进去的port构造一个Inet_Addr的对象

注意,这只是个TCP的socket的接口,不是TCP服务器本身。这个类只是用于服务于我们在TCPServer中去构建一个个的Socket

class TcpSocket : public Socket
{
public:
    TcpSocket()
    :_sock_fd(gsockfd)
    {}

    virtual int SocketOrDie()
    {
        _sock_fd = socket(AF_INET,SOCK_STREAM,0);
        if(_sock_fd < 0)
        {
            LOG(LogLevel::ERROR) << "Tcp socket fail";
            DIE(SOCK_ERR);
        }
        LOG(LogLevel::DEBUG)<<"listen socket success";

        return _sock_fd;
    }

    virtual bool BindOrDie(int port)
    {
        if(_sock_fd==gsockfd)
        {
            return false;
        }
        InetAddr inet_addr(port);
        int n = ::bind(_sock_fd,inet_addr.NetAddr(),inet_addr.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind error";
            DIE(BIND_ERR);
        } 
        LOG(LogLevel::DEBUG)<<"bind success";
        return true;
    }

    virtual bool ListenOrDie()
    {
        if(_sock_fd==gsockfd)
        {
            return false;
        }

        int n = ::listen(_sock_fd, BACKLOG);
        if(n<0)
        {
            LOG(LogLevel::ERROR)<<"listen false";
            DIE(LISTEN_ERR);
        }
        LOG(LogLevel::DEBUG)<<"listen success";

        return true;
    }

    virtual int Accept()
    {

    }

    virtual void Close()
    {
        ::close(_sock_fd);
    }

    virtual ~TcpSocket()
    {
        
    }
private:
    int _sock_fd;
};

http是基于TCP协议的,所以http是需要基于TcpServer的,一层一层往上搭。

  TcpServer:

loop模块,核心逻辑

loop模块有两个任务,accept和IO

如何设计这个Accept模块呢?

        以下是博主自己的思考(思考怎么设计参数、如何传参也是开发中最重要的一步)

        在TcpServer层,肯定希望直接能通过我们封装好的Ptr调一个Accept来获得一个可以直接用的tcpsocket(多态情况下肯定是需要被基类去控制的)。不过此处的Socket类被我们实现成了一个虚类,必须使用指针去实现(这也是为什么_ListenSockPtr被设计成一个基类的指针)。

那么TcpSocket层次的Accept方法就可以返回一个构造好的Socket的智能指针。值得注意的是,此处的返回的这个智能指针需要是shared的而非unique。

相当于用父类指针指向了一个子类的实例化对象

        再来看Sockegt层次中Accept的参数——说白了,我们封装的Accept函数就是处理好 真正的accept 的两类返回值:打开的 ''打工人sockfd'' 以及了解客户端信息的struct sockaddr_in。

        结合上述逻辑,我觉得可以在上层调用时传一个Client的InetAddr*类型参数,作为输出型参数,保留::accept的两个输出型参数的sockaddr_in的信息。另外用accept的返回值构建一个shared实例,返回其指针到TcpServer层

client是用来获取客户端的信息的,peer_p是一个原生的sockaddr_in结构体,用来给peer_p设置信息的。

现在的Accept实际拿到的是一个Socket基类指向的TcpSocket派生类的对象,其中的成员变量_sock_fd就是刚刚accept的newsockfd

所以需要在Socket类中再去封装对应的读写方法,这样在TcpServer层次才能直接去读写这个被封装起来并且被传回到TcpServer的Socket。(这样去Socket中封装读写方法的设计,可以方便TcpServer层次直接使用读写接口

        

我们希望的:

HttpServer

别忘了,尽管我们已经可以在Tcp层次直接调Recv和Send,但是我们为了保证字节流的完整性,还需要进行对应的序列化与反序列化。先大概实现一个recv与send叭。

然后就是调用其他的进程、线程或线程池来把具体的处理函数调起来,此处我们选择进程

子进程没有必要继续继承这个listen_fd。

既然任务都交给孙子进程了,父进程就等待并回收子进程即可。并且父进程也可以关闭他accept到的文件描述符

HttpServer需要遵守一定的规则,所以还需要一个HttpProtocol,最后调用HttpProtocol的也该命名为Http.cc。

        现在需要进一步把文件描述符丢给创建的孙子进程,也就是上面注释掉的handler。

除了sockfd丢给handler,刚刚在Accept中的输出型Client也可以用起来:

处理方法丢给上层,直接调用一个_handler就可以了。

因为IO的具体逻辑包括解析、是否读完整等。所以,所谓解析、与完整性的判断,就是交给Http层次就可以了。


HTTP一定都是基于Tcp协议的:

关于文件描述符是如何传进来:

        

class HttpServer : public nocopy
{
public:
    HttpServer(int port = gport)
    :_port(port)
    ,_tsvr(std::make_unique(_port))
    {}

    void Start()
    {
        _tsvr->InitServer([this](SockPtr sockptr, InetAddr client){
            return this->HandlerHttpRequest(sockptr,client);
        });

        _tsvr->Loop();
    }

    //处理核心逻辑的函数
    bool HandlerHttpRequest(SockPtr sockptr, InetAddr client)
    {

    }

考虑在TcpServer中加一个Init模块来单独初始化handler,这样在HTTP层次,构建TcpServer的时候才能更方便的去传lambda

语法tips:

现在有一个小小的报错:

lambda表达式返回的是一个临时的函数对象,临时变量具有常性,如果用一个&接受会导致权限的放大,所以可以选择赋值或者const&(&会放大权限,const保证权限不被放大)

初代版本(DEMO 0.0)

目前为止,整个程序已经可以跑起来了。

直接用浏览器访问当前服务器,就会被accept。

先贴一下调过后的代码:自顶向下,依次是HTTP、TCP、SOCKET

#pragma once

#include 
#include 
#include "TcpServer.hpp"
#include "HttpProtocol.hpp"//现在这还是一个空的头文件

const uint16_t gport = 8080;

using namespace Tcpserver;

class HttpServer : public nocopy
{
public:
    HttpServer(uint16_t port = gport)
    :_port(port)
    ,_tsvr(std::make_unique(_port))
    {}

    void Start()
    {
        _tsvr->InitServer([this](SockPtr sockptr, InetAddr client){
            return this->HandlerHttpRequest(sockptr,client);
        });

        _tsvr->Loop();
    }

    //处理核心逻辑的函数
    bool HandlerHttpRequest(SockPtr sockptr, InetAddr client)
    {
        LOG(LogLevel::DEBUG)<<"get a new client fd is "<Fd()<<" the addr is "
        < _tsvr;
};
#pragma once
#include 
#include 
#include 
#include "Socket.hpp"
#include "Common.hpp"

using namespace SocketModule;

namespace Tcpserver
{
    // 子进程调用该方法,把处理任务交给上层
    using handler_t = std::function;

    class TcpServer : public nocopy
    {
    public:
        TcpServer(uint16_t port)
            : _ListenSockPtr(std::make_unique()), _port(port)
        {
            _ListenSockPtr->BuildTcpSocketMethod(_port);
        }

        void InitServer(const handler_t &handler)
        {
            _handler = handler;
        }

        void Loop()
        {
            _running = true;
            while (_running)
            {
                // 1.Accept
                InetAddr Client;
                // Clinet在当前语境下,只是用来获得一个客户端的信息,
                // 获得客户端信息之后如果不使用,这个变量可以直接释放,
                // 所以建议直接当作栈变量而非去堆上new
                SockPtr newsock = _ListenSockPtr->Accept(&Client);
                LOG(LogLevel::DEBUG) << newsock->Fd();
                if (!newsock->IsAcceptlegal() || nullptr == newsock)
                {
                    // 拉客失败就重新再拉
                    // if(nullptr == newsock)
                    // LOG(LogLevel::DEBUG)<<"nullptr == newsock";
                    // if(!newsock->IsAcceptlegal())
                    // {
                    //     LOG(LogLevel::DEBUG)<<"IsAcceptlegal";
                    //     //exit(9);
                    // }
                    continue;
                }
                LOG(LogLevel::DEBUG) << Client.NetName();

                // 2.进行IO
                // 创建进程处理
                pid_t _pid;
                _pid = fork();
                if (_pid == 0)
                {
                    _ListenSockPtr->Close();
                    // 避免父进程wait,交给孙子进程,被OS管理
                    if (fork() > 0)
                        exit(0);
                    // 交给上层
                    _handler(newsock, Client);
                    exit(0);
                }
                newsock->Close();
                waitpid(_pid, nullptr, 0);
            }
            _running = false;
        }

        ~TcpServer()
        {
            _ListenSockPtr->Close();
        }

    private:
        std::unique_ptr _ListenSockPtr;
        uint16_t _port;
        bool _running;
        handler_t _handler;
    };

}
#pragma once
#include 
#include 
#include 
#include 
// 网络四件套
#include 
#include 
#include 
#include 

#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogModule;
using namespace Inet_Addr;

namespace SocketModule
{
    class Socket;
    using SockPtr = std::shared_ptr;

    // 基类,规定创建socket的方法
    // 提供若干个、固定模式的方法
    class Socket
    {
    public:
        virtual ~Socket() = default;
        virtual int SocketOrDie() = 0;
        virtual bool BindOrDie(uint16_t port) = 0;
        virtual bool ListenOrDie() = 0;
        virtual SockPtr Accept(InetAddr *client) = 0;
        virtual bool Recv(std::string *out) = 0; // Recv的参数是一个输出型参数
        virtual bool Send(std::string &in) = 0;  // Send的参数是一个输入型参数
        virtual void Close() = 0;
        virtual bool IsAcceptlegal() = 0;
        virtual int Fd() = 0;

#ifdef _WIN
        void BuildTcpSocketMethod()
        {
            SocketOrDie();
            BindOrDie();
            ListenOrDie();
        }
#else
        void BuildTcpSocketMethod(uint16_t port)
        {
            SocketOrDie();
            BindOrDie(port);
            ListenOrDie();
        }

        void BuildUdpSocket() {}
#endif
    private:
    };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket(int sock_fd = gsockfd)
            : _sock_fd(sock_fd)
        {
        }

        virtual int SocketOrDie() override
        {
            _sock_fd = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock_fd < 0)
            {
                LOG(LogLevel::ERROR) << "Tcp socket fail";
                DIE(SOCK_ERR);
            }
            LOG(LogLevel::DEBUG) << "listen socket success";

            return _sock_fd;
        }

        virtual bool BindOrDie(uint16_t port) override
        {
            if (_sock_fd == gsockfd)
            {
                return false;
            }
            InetAddr inet_addr(port);
            int n = ::bind(_sock_fd, inet_addr.NetAddr(), inet_addr.NetAddrLen());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "bind error";
                DIE(BIND_ERR);
            }
            LOG(LogLevel::DEBUG) << "bind success";
            return true;
        }

        virtual bool ListenOrDie() override
        {
            if (_sock_fd == gsockfd)
            {
                return false;
            }

            int n = ::listen(_sock_fd, BACKLOG);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "listen false";
                DIE(LISTEN_ERR);
            }
            LOG(LogLevel::DEBUG) << "listen success";

            return true;
        }

        virtual SockPtr Accept(InetAddr *client) override
        {
            if (nullptr == client)
            {
                return nullptr;
            }
            sockaddr_in *peer_p = new sockaddr_in();
            socklen_t peer_len = sizeof(*peer_p);
            LOG(LogLevel::DEBUG)<<"Ready to accept";
            int newsockfd = ::accept(_sock_fd, CONV(peer_p), &peer_len);
            LOG(LogLevel::DEBUG)<<"accept success";
            
            // client.Set TODO!!!!!!!!
            client->SetSockAddr(*peer_p, peer_len);
            return std::make_shared(newsockfd);
        }

        inline bool IsAcceptlegal() override // Accept中返回的newsockfd可能是accept失败了的,所以需要检查
        {
            if (_sock_fd < 0)
                return false;
            return true;
        }

        virtual bool Recv(std::string *out) override
        {
            char in_buffer[SIZE];
            int in_size = ::recv(_sock_fd, in_buffer, SIZE - 1, 0);
            if (in_size > 0)
            {
                in_buffer[in_size] = 0;
                *out = in_buffer;
                return true;
            }
            return false;
        }

        virtual bool Send(std::string &in) override
        {
            int _size = ::send(_sock_fd, in.c_str(), in.size(), 0);
            if (_size > 0)
                return true;
            return false;
        }

        virtual void Close()
        {
            if (_sock_fd < 0)
                return;
            ::close(_sock_fd);
        }

        virtual ~TcpSocket() override
        {
        }

        virtual int Fd() override { return _sock_fd; }

    private:
        int _sock_fd;
    };

    // class UdpSocket : public Socket
    // {
    // public:
    //     virtual ~UdpSocket()
    //     {
    //     }

    //     virtual int SocketOrDie() = 0;
    //     virtual bool BindOrDie() = 0;
    //     virtual bool ListenOrDie() = 0;
    //     virtual int Accept() = 0;
    //     virtual void Close();

    // private:
    // };

}

在浏览器(客户端)中直接访问当前我的服务器,发现在尝试连接四次之后卡住了。可能是连接超时等问题。毕竟现在的服务器没有返回任何的资源

如果我们打印一下收到的http request:

 再仔细看看第一排的请求行

其实真正的http请求只有第一排

其他的都是请求报头,都是k-v形式的

很有趣的发现,在打印完第一次之后,空格空了两行,其中的一个空格是LOG自带的,说明整个http请求还自带一个空格,第一排都是GET+空的URL+版本号  满足最开始的宏观理解。

连接成功!


DEMO 1.0

尝试手写一个返回的消息,被send到对应的fd中去。

再次观察Response的结构:

                

在HTTP(HyperText Transfer Protocol,超文本传输协议)中,status-line(状态行)是HTTP响应消息中的第一个行,它提供了关于服务器响应的基本信息。状态行由三个部分组成,分别是:

  1. HTTP版本:指示服务器使用的HTTP协议的版本,例如HTTP/1.1

  2. 状态码(Status Code):一个三位数的代码,用来说明请求的处理结果。状态码分为五类:

    • 1xx:指示信息——请求已接收,继续处理。

    • 2xx:成功——请求已成功被服务器接收、理解,并接受。

    • 3xx:重定向——需要后续操作才能完成请求。

    • 4xx:客户端错误——请求包含语法错误或无法完成请求。

    • 5xx:服务器错误——服务器在处理请求的过程中发生了错误。

  3. 原因短语(Reason Phrase):一个简短的文本描述,用来提供状态码的额外信息。例如,对于状态码404,原因短语通常是Not Found

一个典型的状态行示例如下:

HTTP/1.1 200 OK

这表示服务器使用的是HTTP/1.1版本,状态码是200,表示请求成功,而OK是对应的原因短语,进一步说明请求已经成功处理。

        状态行是HTTP响应消息的开始,它后面跟着响应头部(headers)和可选的响应主体(body)。状态行为客户端提供了关于请求结果的快速概览,使得客户端能够根据状态码和原因短语来决定如何进一步处理响应。

说白了,现在就是假装返回一个假的、已经被反序列化的"Response",现在只要status_line以及Body两部分组成即可,暂时不用对应的响应报头。

        

首先写第一排的内容,string status_line HTTP/1.1 200 OK

 //demo 1.0 硬编码来返回
 //sep是状态行的
,Backline是空行,本质也是一个

 std::string status_line = "HTTP/1.1 200 OK" + Sep + Backline;

        再让AI生成一个html的body,作为Body

//demo 1.0 硬编码来返回
        //sep是状态行的
,Backline是空行,本质也是一个

        std::string status_line = "HTTP/1.1 200 OK" + Sep + Backline;
        std::string body = 
                   "
                    
                   
                   
                    Hello World
                   
                   
                   

LOVE YOU Ronin007 回家吃饭饭 "; std::string http_response = status_line+body; sockptr->Send(http_response); //可以用这个弱智的硬编码去逗一逗女朋友的傻笑,如果你有女朋友的话

出来的效果类似于:


DEMO 2.0

                --------------------------------------加入HttpProtocol部分

现在就可以考虑读取请求,对请求进行分析处理了!

如何对http请求进行序列化和反序列化呢(对http进行协议化)?

要确定两个事情:

1.读取请求的完整性 

2. 完整http反序列化,http response序列化


现在,对http进行协议化。

直接利用两张图来完成

 

因为两个报头中都可能包含多个string,所以选择用vector来记录

观察这个Http请求,思考如何取出各个数据:

GET /favicon.ico HTTP/1.1
Host: 81.70.12.246:8080
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Referer: http://81.70.12.246:8080/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

首先,提取出request的整个请求行(就是提取一个子串),提取了子串之后还要想办法获得几个子结构。

 第二排表示请求发到谁去了,发到哪一个主机的哪一个端口。

第三排 长连接(暂时不理会),

第五排 User-Agent(后文中分享)

Accept:表示能接受以下的内容,也就是正文到底是accept后的哪一种类型。

刚刚提到的UserAgent:

 

User-Agent 是一个 HTTP 请求头部字段,它用于识别请求发起者的信息,比如浏览器类型、操作系统、浏览器版本以及它所运行的设备或软件。这个字段通常由客户端(如 Web 浏览器)自动设置,并且可以在服务器端的 HTTP 响应中看到。

User-Agent 头部的主要目的是帮助服务器确定请求的设备和软件环境,以便它可以返回最适合该环境的内容或进行特定的优化。例如,一个移动设备的浏览器可能会在 User-Agent 字符串中包含设备型号和浏览器版本信息,这样服务器就可以根据这些信息提供适合移动设备显示的页面布局和资源。

比如,以上两张图就能看出发出请求方的操作系统,一个是win,一个是基于Linux的安卓。

        因为request或者response都需要提取出第一排的内容,所以这个ParseFirstLine应该写到Common.hpp中去

直接实现即可:

在HttpServer中调用这个内容,再打印看看分析完之后还剩下哪些字段

做好相应的debug,发现我们已经成功分离request的请求行

void Deserilize(std::string &str)
    {
        LOG(LogLevel::DEBUG)<<"##################################";
        LOG(LogLevel::DEBUG)<<"before
"<

可以看到,请求的url是/

如果换个位置做访问测试:

请求到的url就是/a/b/c/d.html

tips:简单介绍一下wwwroot以及index.html

wwwroot 是一个常见的术语,通常用于描述网站的根目录(root directory)。

  • 根目录wwwroot 是一个文件夹,通常用于存放网站的所有文件和资源。它是网站的“家目录”,所有网页、图片、脚本、样式表等文件都存储在这个目录下。

  • Web服务器的默认目录:在许多Web服务器(如Apache、Nginx、IIS等)中,wwwroot默认的网站根目录。当用户通过浏览器访问网站时,服务器会从这个目录中查找并提供相应的文件。

示例

假设你的网站地址是 https://example.com,那么:

  • https://example.com 默认会访问 wwwroot 目录下的默认文件(通常是 index.html)。

  • 如果用户访问 https://example.com/about.html,服务器会从 wwwroot 目录中查找 about.html 文件。

文件结构

一个典型的 wwwroot 目录结构可能如下:

wwwroot/
├── index.html
├── about.html
├── contact.html
├── images/
│   ├── logo.png
│   └── background.jpg
├── css/
│   └── styles.css
└── js/
    └── script.js

index.html 是一个HTML文件,通常被用作网站的默认首页

.css是一种描述HTML的文件,让页面更好看

现在分离  请求报头:简单的字符串处理任务

 void ParseHeader(std::string &str)
    {
        /*
        调用ParseFirstLine去解决问题,
        可能有三种情况:
        out正常;return false&&out为空;return true&&out空串
        分别对应:正常给出来、已经找完了、找到了空行
        */
        while (true)
        {
            std::string headler_line;
            bool flage = ParseFirstLine(str, &headler_line, ::Sep);
            if (flage && !headler_line.empty())
            {
                _req_head.push_back(headler_line);
            }
            else if(!flage && headler_line.empty())
            {
                break;
            }
            else if(flage && headler_line.empty())
            {
                continue;
            }
        }
        
    }

现在发下left str之后已经没有内容了(因为现在body为空)

现在的整个报头还是字符串,想把它的KV属性都拆出来:

DEMO 3.0

               -------------------------------------使用html在wwwroot中完成code=404和code=200的情况描述

家目录wwwroot

刚才提到,如果想有一个http服务,必须要构造一个http的家目录,文件名,比如:wwwroot

后端服务如果想被访问,决定了站点必须要有一个“默认首页”

        

 web根目录名字都是被隐藏了的。

www.baidu.com和www.baidu.com/index.html是一个东西,可以在当前环境中使用mkdir指令和touch指令创建这两个文件。

                ​​​​​​​        

用户真正想访问的是被放到http请求的uri部分。

   tips:

     URL(Uniform Resource Locator,统一资源定位符)和 URI(Uniform Resource Identifier,统一资源标识符)都是用于标识资源的字符串,但它们的含义和用途有所不同。

URI可以进一步被分成URL或者URN。URI不一定标识清楚了资源具体在哪里。

所以,URI就是去获得用户想访问的资源的地址,并且这个路径都是建立在默认路径之上的,作为服务器,我们需要加上这个路径

浏览器的uri是默认忽略了这个根目录,服务器需要自动加这个前置路径,才能找到用户希望找到的资源。

        uri知道了用户想用什么,需要一个HttpResponse,把这个文件塞进去。但是uri是在Request的字段内,所以在Request中,还需要一个GetContent方法,在request中去读文件。

把客户请求的文件拿出来(临时做法,这么拿只能拿文字信息,无法正确获得二进制的文件、诸如图片、视频等):

        ​​​​​​​        ​​​​​​​        

Public中再设计一个对应的调用方法即可。


class Response

Build--------------Response不可缺少的一环

不同于Request是从浏览器处拿到然后手动反序列化出来,Response的构建过程需要我们使用各种信息来Build。比如当前服务器的版本号,对于发起的请求的状态码、状态描述等。

如何根据用户想要的内容构建回复呢?这就是Build模块

对于任何HTTP,任何请求,都必有应答。

如果请求的资源不存在该怎么办?这就是状态码存在的意义,也是人们常说的404 Not Found

今天只了解404和200即可

关于为什么需要一个HTTP版本在报头,笔者借助AI生成了一个小tips:

HTTP协议的版本信息在Request和Response报文中扮演着重要角色。具体来说:

  1. Request中的HTTP版本(如HTTP/1.1)表示:
  • 客户端(通常是浏览器)支持的HTTP协议版本
  • 决定了客户端会发送哪些请求头字段
  • 影响客户端对持久连接、分块传输等特性的支持 示例:HTTP/1.1请求会自动包含Host头字段,而HTTP/1.0则不会
  1. Response中的HTTP版本(如HTTP/1.1)表示:
  • 服务器实际使用的HTTP协议版本
  • 决定了服务器会返回哪些响应头字段
  • 影响服务器对特性(如Keep-Alive)的支持程度 示例:HTTP/1.1服务器会默认保持连接,而HTTP/1.0服务器需要显式设置Connection: keep-alive

版本差异的应用场景:

  • 当客户端发送HTTP/2.0请求但服务器只支持HTTP/1.1时,服务器会降级响应
  • 不同版本支持的压缩算法可能不同(如HTTP/2支持HPACK头部压缩)
  • 缓存控制机制在不同版本间有差异(HTTP/1.1引入更多缓存控制指令)

在实际通信中,最终使用的HTTP版本是客户端和服务器都支持的最高共同版本。

private:
    std::string Code2Desc(int status_code)
    {
        std::string ret;
        switch (status_code)
        {
        case 404:
            ret = "Not Found";
            break;
        case 200:
            ret = "OK";
            break;
        default:
            break;
        }

        return ret;
    }
public:
    void Build(HttpRequest& req)
    {
        std::string& content = req.GetContent();
        if(content.empty())
        {
            _status_code = 404;
            _status_desc = Code2Desc(_status_code);
        }
        else 
        {
            _status_code = 200;
            _status_desc = Code2Desc(_status_code);
        }
    }

如果用户要访问一个不存在的页面,我们需要返回404对应的文件资源(此处可以让AI生成一个前端的html文件),那么就需要去更改一下用户想访问的URI:

public:
    void Build(HttpRequest& req)
    {
        std::string& content = req.GetContent();
        if(content.empty())
        {
            _status_code = 404;
            req.SetURI(Page404);
            content = req.GetContent();
        }
        else 
        {
            _status_code = 200;
        }
        _status_desc = Code2Desc(_status_code);
    }

然后是Serilize:把要返回的内容都进行序列化

Deserilize是把一个字符串给解析出来内容,是输入型参数

    Serilize是一个输出型参数,应该用指针。

可以试着直接用指令连接:

        ​​​​​​​        ​​​​​​​        ​​​​​​​        

一个空行,然后就是网页的内容

        ​​​​​​​        

还可以试试从浏览器去访问,浏览器拿到这些标签性质的文件之后还会解析,生成一个小小的前端页面。

index.html作为默认访问是需要特殊处理的

不过,直接访问的/也应该把根目录放出来,可以特殊处理一下:

现在直接输入ip+port:比如81.70.12.246:8080

快拿去逗逗你的宠物。

前端代码直接让AI生成即可。

如果访问一个不存在的网址(比如/a/b/c/d.html):


DEMO 4.0

                         ---------------------------------------------结合前端,加入图片

前端开发其实就是写wwwroot里的内容,wwwroot外面的内容才是后端完成的。

读者朋友看了这么久,学个入门前端来放松下:

HTML 简介 | 菜鸟教程

借助教程来看一个简单的HTML标签——a标签。换句话说,就是前端中各种链接的点击

让AI生成一个简单的电商前端html代码(所有的代码都在文末的git链接上,本文一共分上下两篇,在第二篇的末尾)

a标签表示这个链接会发起的html请求,只要把各个界面的a标签都设置到希望跳转到的a标签即可。


终于想起来还没有设置Response的header,依然是用一个unorderedmap去实现,今天只加两个值,一个是content_type,一个是content_length

176排,设置header内容;181排,将unordered_map中的内容全部加在HttpResponse里去

只不过目前为止,我们只加了一个属性,就是Content_Length

        

再了解一个属性,content_type

        HTTP作为超文本传输协议,不仅可以传输文本,还能传输图片、视频等“超文本”,比如上述的html里,只要标明图片名称,并且在wwwroot的image文件夹下是真的有这些图片,就能完成任务了。

        ​​​​​​​        

对照刚刚的图片为什么没显示出来,是因为图片内容传输失败了。

简单说明是如何去获得图片的:

 

浏览器会去自动进行一个请求图片的任务。

浏览器对发过去的html进行解析,发现还需要去找三张图片,于是回到对应的image文件夹下去找。

但是,原来的SetContent方法是用ifstream直接去读,这是不正确的。因为图片是以二进制形式传输,二进制中可能遇到很多的/0等,直接读到一半的时候就失败了,所以需要一个标准的GET方法来重新传资源。

GET方法

int SetContent()
    {
        std::ifstream in(_url,std::ios::binary);
        if(!in.is_open()) return OPEN_ERR;
        in.seekg(0,in.end);
        int filesize = in.tellg();
        in.seekg(0,in.beg);

        _content.resize(filesize);
        in.read((char*)_content.c_str(),filesize);
        in.close();
        return 0;
        // std::ifstream file(_url);
        // if (!file.is_open())
        // {
        //     LOG(LogLevel::ERROR) << "OPEN FAIL";
        //     return OPEN_ERR;
        // }

        // std::string line;
        // while (std::getline(file, line))
        // {
        //     _content += line;
        // }

        // file.close();

        return 0;
    }

下面是我们之前的SetContent的方法,现在是新版本的,通过控制文件大小和文件偏移量解决问题,一次性把整个文件都读进去。

这下就能看到了所有的图片了:

理解浏览器的强大

如果打印出我们的HttpResponse

会发现全是乱码,但是浏览器能正确识别这些内容,形成我们的网页。

content_type:

content_type是响应报头的另一个字段,用于告诉浏览器数据的类型。浏览器需要知道一个文件的类型,是根据分析后缀来的,会将分析得到的后悔写成一个MIME类型的样子供浏览器识别。

后缀会转换成对应的字段,赋值到content_type里去

找后缀(suffix):

把对应的content-type信息加到映射表以及vector中去。


        文章内容太多,分两次发,下一篇会重新介绍如何GET POST ,客户端如何call整个调用过程等内容..............

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

搜索文章

Tags

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