最新资讯

  • 【linux】网络基础(四)HTTP协议,域名,url,认识http的请求和响应,Fiddler Classic,Postman,httpserver服务器的实现,recv

【linux】网络基础(四)HTTP协议,域名,url,认识http的请求和响应,Fiddler Classic,Postman,httpserver服务器的实现,recv

2026-01-28 21:26:44 栏目:最新资讯 2 阅读

小编个人主页详情<—请点击
小编个人gitee代码仓库<—请点击
linux系统编程专栏<—请点击
linux网络编程专栏<—请点击
倘若命中无此运,孤身亦可登昆仑,送给屏幕面前的读者朋友们和小编自己!


目录

    • 前言
    • 一、两个预备知识
      • 域名
      • url
    • 二、http的请求和响应
      • http请求
      • http响应
    • 三、三个工具
      • telnet
      • Fiddler Classic
      • Postman
    • 四、httpserver服务器
      • HttpServer.hpp
        • 基础框架
        • Start
        • ThreadRun
      • HttpServer.cc
    • 五、测试
    • 六、源代码
      • makefile
      • HttpServer.hpp
      • HttpServer.cc
      • Sock.hpp
      • Log.hpp
    • 总结


前言

【linux】网络基础(三)TCP服务端网络版本计算器的优化,Json的使用,服务器守护进程化daemon,重谈OSI七层模型——书接上文 详情请点击<——,本文会在上文的基础上进行讲解,所以对上文不了解的读者友友请点击前方的蓝字链接进行学习
本文由小编为大家介绍——【linux】网络基础(四)HTTP协议


一、两个预备知识

  1. 应用层协议是我们自己定制的,在之前的文章中小编已经带领大家定制了自定义协议并且实现了网络版计算器,那么本文小编带领大家认识一下成熟的,好用的应用层协议:HTTP协议((hypertext transport protocol超文本传输协议)
  2. 下面小编先学习两个预备知识,域名和url然后再来学习HTTP协议更容易上手

域名

  1. 我们使用浏览器进入百度通常要输入网址www.baidu.com,并且按下回车之后,前面会自动补齐https,即访问百度使用的是 https://www.baidu.com/ 通常我们把这个叫做域名,前面以https开头那么代表的是使用的https协议,所以浏览器如果我们不显示的输入协议,那么浏览器默认使用的协议大多是https协议,少部分是http
  2. 那么我们知道我们访问百度主页本质上访问的还是百度的服务器,既然是访问百度的服务器那么就需要两个东西必不可少,没错,服务器的IP地址和端口号port,但是为什么我们在 https://www.baidu.com/ 这个域名中并没有见到服务器的IP地址和端口号port呢?下面小编带领大家探究一下
  3. 首先我们在搜索中输入cmd,打开命令提示符,即终端
  4. 然后输入百度的网址www.baidu.com,此时会看到如上字段,那么此时我们最关心的是以点分十进制分隔的一个IP地址 39.156.70.239
  5. 所以我们直接拿这个 39.156.70.239 在浏览器上搜索,按下回车
  6. 此时我们神奇的进入到了百度主页,即此时我们使用的是 http://39.156.70.239/ 访问的百度主页,并且在前面默认浏览器帮我们补齐了http,所以可以说明,其实域名本身就可以经过域名解析,解析成IP地址,小编,我已经成功的见到了IP地址,可是端口号呢?为什么我们没有看见百度的端口号呢?
  7. 其实诸如百度等常见的端口号已经被内置在了浏览器中,当我们使用百度的域名去访问百度主页的时候,浏览器会自动的根据域名然后经过域名解析解析成IP地址然后去自动匹配内置在浏览器中对应的端口号
  8. 那么https协议使用的默认端口号是443,http协议使用的默认端口号是80,即如果我们想要使用https协议那么可以给浏览器指明443,如果我们想要使用http协议那么就可以给浏览器知名80,所以呢?我们该如何指明呢?那么通过 IP地址:端口号 即可

  9. 例如我们使用冒号分隔IP地址和端口号,指明使用80端口号 39.156.70.239:80,所以就会自动匹配http协议

  10. 例如我们使用冒号分隔IP地址和端口号,指明使用443端口号 39.156.70.239:443,所以就会自动匹配https协议

url

  1. 相信喜欢打王者荣耀的读者友友,都听说过听安,那么听安经常会说,打出那六个英文字母,YGking(意义代表的是元歌王),那么小编使用浏览器搜索一下YGking

  2. 接下来我们点击第一个哔哩哔哩的视频,然后点击右上方王者荣耀听安的主页
  3. 所以我们就拿到了如上界面,即王者荣耀听安的主页,而我们关注的不是YGking,不是元歌单挑,也不是王者荣耀听安,而是是哔哩哔哩王者荣耀听安对应的浏览器中最上方的网址
// 王者荣耀听安主页的网址
https://space.bilibili.com/430044260?spm_id_from=333.788.upinfo.head.click
  1. 所以从此以后,如果你想跟你的好朋友分享王者荣耀听安,那么只需要将王者荣耀听安主页的网址发给他,然后你好朋友只要拿着这个网址就可以唯一的访问到王者荣耀听安的主页,通常的我们将这个网址叫做url(uniform resource locator统一资源定位符)
  2. 所以有了url,那么所有网络上的资源(图片,音频等),都可以使用唯一的一个"字符串"标识,并且可以获取到,那么下面我们来详细认识一下url的格式
  3. 那么第一个字段通常是https://或者http://格式,是进行协议的选择然后冒号两个斜杠进行分隔,第二个字段是登录信息,目前几乎不使用了,可以省略,所以我们不关心,然后分隔符@也可省略,第三个字段是服务器的地址,即虽然填写的是一个域名,但是我们要知道这个是可以被经过域名解析然后转化为服务的IP地址的,然后分隔符是冒号,通常冒号也可省略,接下来就是服务器的端口号通常也可以省略,因为浏览器已经将很多的常用服务器对应的端口号已经内置了,接下来是 / 其中这个 / 我们称之为web根目录,这个目录有可能是根目录同样也有可能是采用的相对路径的根目录,那么 /dir/index.htm 我们称之为带层次的文件路径,其实就是要访问的资源的存放路径
  4. 我们知道,我们要上网,那么我们的网络行为无非就两种
    (一)把别人的东西拿下来,例如,刷抖音,将抖音服务器上的短视频资源拿到本地抖音客户端
    (二)把自己的东西传上去,例如,我们登录王者荣耀,那么首先就要发起登录请求,这个登录请求,就是将自己的用户信息等字段传上去
  5. 所以说对于用户来讲,那么本次网络行为就有可能是把自己的东西传上去,所以就要使用到接下来的分隔符?紧接着就是kv风格的以等号=分隔的字符串,为什么是kv?例如user=tingan&password=1433223,那么前面的这就是将用户名和密码传上去,如果有多个需要上传的字段,那么中间采用与符号&进行分隔,当然如果用户不需要把自己的东西传上去那么?k=v就可以省略
  6. 那么最后一个字段就是#ch1,即片段标识符,例如这个网页上有循环显示的图片片段,最后一个字段就是标识循环到了第几个图片片段
  7. 此时url介绍完毕,同时我们还注意到,url中采用了很多分隔的字符://?&#=@所以如果用户去搜索查询这些分隔符会不会影响到url呢?下面小编搜索一下
https://cn.bing.com/search?q=%3A%2F%2F%3F%26%23%3D%40&qs=n&form=QBRE&sp=-1&lq=0&pq=%3A%2F%2F%3F%26%23%3D%40&sc=12-8&sk=&cvid=C39C5BAD36D548818AF5B0A87C56BA0B
  1. 所以此时没有影响到url,查询成功,反馈没有对应的结果,并且我们观察上面的网址有很多的%形式的字符,那么这是什么意思呢?为什么没有影响到url呢?因为我们的字符被编码了
  2. 少量的情况,提交或者获取的数据本身可能包含和url的特殊字符冲突的字符,这时候就要求BS双方(B代表的是browser浏览器,S代表的是server服务器)进行Encode编码和Decode解码
  3. 那么如何理解Encode呢?其实既然是特殊字符,那么就有应该在ASCII码表中存在,ASCII码表上有256个字符,那么256是2的8次方,所以我们使用8个比特位就完全可以将特殊字符进行表示
  4. 那么url进行转码的规则规定,需要将转码的字符转换成16进制,需要转码的字符可以使用8个比特位进行表示(不够的话左侧补零),那么4个比特位可以转换成一个16进制数,所以8个比特位中的右侧四个比特位转换为16进制数作为y,8个比特位中的左侧的四个比特位转换为16进制数作为x,所以8个比特位的数就被转换成了16进制数xy,那么规定在xy前加上%此时完成编码,即%xy,那么为什么要转换成16进制?因为有可能需要转换的字符是汉字,汉字同样也需要经过编码后才能发送
  5. 其实我们不需要关心Encode编码和Decode解码,因为网上有现成的转换工具,我们可以直接拿来使用
https://cn.bing.com/search?q=%3A%2F%2F%3F%26%23%3D%40&qs=n&form=QBRE&sp=-1&lq=0&pq=%3A%2F%2F%3F%26%23%3D%40&sc=12-8&sk=&cvid=C39C5BAD36D548818AF5B0A87C56BA0B
  1. 所以我们就在网络上直接搜索url编码在线转换即可 详情请点击<——,将查询的://?&#=@对应编码后的%3A%2F%2F%3F%26%23%3D%40进行解码转换查看,如下无误

  2. 同样的,我们也可以进行编码,如下无误

二、http的请求和响应

  1. 所以下面小编就将http的请求和响应的格式分别画出来,我们现在理论层面见一见http的请求和响应的样子

http请求

  1. 所以对于http的请求,一共分为四部分,依次是请求行,请求报头,空行,请求正文,其中请求行和请求报头的结尾以及空行必须以 结尾,其中 是回车,回到当前行的开头, 是竖直换行,所以合起来就是回到下一行的开头
  2. 那么在请求行中的各个字段依次是Method代表请求的方法,大约95%的请求都是GET获取,POST发送,那么第二个字段是URL,即url统一资源定位符,这个之前小编文章开头的第二个补充知识url已经进行了讲解,那么第三个字段是当前http的版本,版本可以是1.0 1.1 2.0,主流版本一般是1.1,那么进行写入的时候需要加斜杠/,即HTTP/1.1这种格式,那么末尾是以 结尾,并且请求行各个字段需要以空格分隔
  3. 请求报头中包含的是本次请求的属性以及属性对应值,即是一个kv结构,那么形式是Key: Value注意这里的分隔符是冒号空格,请求报头中的请求属性有多个,那么每一个Key: Value的结尾都需要添加 ,同样的请求报头中还包含一个字段Content-Length: XXX,其中Content-Length的属性意思是请求正文的大小字节数,XXX表示请求正文的实际的大小字节数
  4. 请求正文即我们要上传的内容,如果我们没有要上传的内容的话,请求正文可以省略,问题来了,如何区分请求报头和请求正文
  5. 很简单,http规定请求报头和请求正文中间要包含一个空行 ,此时读取一个请求报文就可以按照如下规则进行读取,首先按行读取请求报文,那么按行读取第一行就是请求行,请求报文中的各个字段是以空格进行间隔结尾是 ,第二行及其往后按行读取的就是请求报头,那么按行读取,按行读取,按行读取,直到读取到一个空行 ,即这一行仅仅包含 ,那么就代表请求报头已经读取完整,往下就按照字节进行读取,继续向下按照字节读取,可是我怎么知道要读取的请求正文有多少字节呢?
  6. 别忘了,请求报头中有一个属性字段是Content-Length: XXX,其中的就XXX表示了请求正文的实际的大小字节数,所以我们就可以按照XXX,从空行向后读取XXX个字节,那么读取上来的我们就当作请求正文
  7. 所以此时我们就可以将http请求完美的进行读取,此时我们在宏观上看待整个http请求报文,虽然请求行和请求报文以及空行中包含了 ,打印出来的话是呈现按行分隔,但是我们也要知道,诸如 实际在存储的时候,也是一个一个的字符,一个字符就是一个字节,所以请求报文整体实际在存储的时候也是一个一个字节的进行存储的

http响应

  1. 那么在见识到了http请求之后,实际上http的响应和http的请求大部分格式都完全相同,所以我们学习了http请求之后,很快的就能上手http响应
  2. 那么http响应也包含四部分,分别是状态行,响应报头,空行,响应正文,那么也是同样的要求,要求状态行,响应报头,空行全部都要以 结尾
  3. 那么我们主要讲解状态行,状态行的字段中第一个字段是HTTP Version即http的版本,同样的,版本可以是1.0 1.1 2.0,主流版本一般是1.1,那么进行写入的时候需要加斜杠/,即HTTP/1.1这种格式,第二个字段是状态码,例如200,404等,第三个字段是状态码的字符串形式的描述,那么第二个字段和第三个字段相信大多数的读者友友都曾经见到过,即对应右图的界面,状态行的各个字段同样需要空格进行分隔,并且状态行的结尾是

三、三个工具

telnet

  1. 在之前的文章中,小编已经讲解了telnet的使用 在第三点进行的讲解,详情请点击<——
  2. 那么小编在文章开头已经在windows的终端cmd上ping出了百度的IP地址 39.156.70.239,那么下面小编使用linux上的telnet我们自己构建http请求报文,然后进行访问,那么百度的端口号是80,在telnet上访问的格式是telnet IP地址 端口号
telnet 39.156.70.239 80

  1. 那么观察到如上左图现象即为连接成功,所以接下来小编先ctrl + ]然后再按下回车,就可以进入telnet的输入,即对应如上右图,所以我们构建发送一个http请求,请求中首先是请求方法我们选择GET获取,然后输入空格,然后就是要进行url的输入了,但是这里我们仅仅是想要获取百度的主页,所以这里我们并不需要输入任何的url那么这里我们简单的输入一个斜杠/即可,然后再输入空格,然后就该选择HTTP的版本,即输入HTTP/1.1,接下来按下回车换行,所以此时就是在请求行的结尾的回车换行,那么由于我们仅仅是发送一个获取请求,所以并不需要带携带任何的请求属性以及请求正文,所以这里我们再次按下回车换行,那么此时就是表示我们输入的回车换行即表示输入了一个空行
GET / HTTP/1.1


  1. 如上,左图输入后按下第一个回车,现象如上的右图,没有反应,这是因为我们这是在输入请求行的回车换行,那么如下继续按下第二个回车才有反应,代表我们此时输入了第二个回车换行,表示输入了空行

  1. 所以此时我们观察上图,此时接收到了百度服务器发来的http响应,那么响应报文的状态行是HTTP/1.1 200 OK,果然第一个字段是版本http的版本HTTP/1.1,第二个字段是状态码200,第三个字段是OK表示状态良好,并且这些字段以空格作为分隔符,并且观察上图确实打印的时候进行了回车换行,说明状态行的结尾是回车换行
  2. 并且我们还看到了上图中响应报头的Content-Length: 29506字段,即表示响应正文的字节数,无误,那么接下来我们继续向下翻

  1. 翻找到了"百度一下,你就知道",这不就是如下左上角百度的标题,无误

  2. 那么我们翻到末尾,那么最后一行就是响应正文,倒数第二行是空行,所以说我们可以得出,响应正文和响应报头之间确实有空行进行间隔

Fiddler Classic

  1. Fiddler Classic是一款抓包工具,你电脑上所有访问网络的行为,即从网络中获取数据,将数据上传到网络中的行为都会被Fiddler Classic抓到并显示到如下界面上,刚刚小编在浏览器上使用百度进行了搜索,所以就被Fiddler Classic进行了抓包,并且将抓取到的进行显示,那么我们分别点击右侧上面和下面界面的Raw,右侧的上半部分即http请求,左侧的下半部分即http响应
  2. 所以如下即http请求,第一行就是请求行,分别是请求方法,url,http的版本,如下无误
  3. 所以如下即http响应,第一行就是状态行,分别是http的版本,状态码,状态字符串版本的描述,如下无误
  4. 可是为什么Fiddler Classic可以将网络的请求与响应的结果都进行抓包呢?原理是什么呢?
  5. 因为Fiddler Classic一旦启动就变成了进程,它运行起来之后,它就变成了一个管理层,本主机上所有的请求,包括http请求要发送到网络上都需要经过我Fiddler Classic,并且远端服务器响应,包括http响应要从网络上发送到本主机上,那么也要经过Fiddler Classic,既然Fiddler Classic可以看得见请求与响应,所以自然它可以得知http的请求与响应的内容了

Postman


  1. Postman是一款用于管理发送的请求的工具,那么我们的http请求就可以使用Postman进行发送,下面我们先点击上图中央偏左的+加号,然后点击中央的GET可以选择发送请求的方法,观察第二个就是POST发送方法,这里我们默认使用GET获取方法即可,所以我们就可以在上图输入要访问的url,那么就是这里我们访问百度的主页,即www.baidu.com,然后点击send发送
  2. 所以此时我们就看到了上图现象,即此时我们http请求访问百度成功
  3. 那么我们点击Preview,然后就可以看到postman已经将百度的主界面的预览进行了加载
  4. 那么我们点击Headers可以看到对于http响应的响应报头的Key: Value进行了划分,如上无误

四、httpserver服务器

  1. 那么下面就由小编带领大家编写一个简单的httpserver服务器,然后我们直接拿浏览器作为客户端发起http请求,然后在进行测试,并且在Fiddler Classic期望观察到测试结果

HttpServer.hpp

基础框架
  1. 那么作为一个服务器,http底层是使用的TCP协议,所以这里我们就使用TCP协议对应的网络套接字接口,那么其实在之前的文章,小编已经对这些网络套接字接口进行封装为了Sock.hpp,这里包含了之后就可以直接使用,在第三点的TCP服务器中的Sock.hpp进行的讲解,详情请点击<——
  2. 并且我们还要使用日志打印信息,所以这里我们将日志的头文件Log.hpp包含就可以直接使用了详情请点击<——
  3. 那么服务端需要知道要绑定的端口号,默认为8080,所以就要有int16_t类型的成员变量端口号port_,以及用于监听的网络文件描述符listensock_,那么对于这个listensock_我们定义为Sock类型的即可,因为Sock有封装的文件描述符,所以在构造函数这里接收端口号,对成员变量端口号进行初始化即可
  4. 这里我们期望当服务器收到一个请求的时候,拿到了sockfd之后,创建线程进行响应处理,所以这里我们还要将线程引进来,那么就要编写线程函数ThreadRun, 由于线程函数是类内成员函数,第一个参数是this指针,类型和pthread_create需要的线程函数的参数类型不匹配,所以要将线程函数ThreadRun使用static修饰成为没有this指针的静态成员函数
  5. 但是静态线程函数ThreadRun需要sockfd,并且静态线程函数ThreadRun有可能会有调用类内的普通的成员变量或者普通的成员函数的需求,所以还需要传参this指针,所以就需要定义一个线程数据ThreadData,将这两个字段设置为公有的成员变量,并且在构造函数中对这两个字段进行初始化
#pragma once

#include 
#include 
#include "Log.hpp"
#include "Socket.hpp"

static const int defaultport = 8080;
class HttpServer;

class ThreadData
{
public:
    ThreadData(int fd, HttpServer* s)
        : sockfd(fd)
        , svr(s)
    {}
public:
    int sockfd;
    HttpServer* svr;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {}

    void Start();
    static void* ThreadRun(void* args);
    
    ~HttpServer()
    {}
private:
    uint16_t port_;
    Sock listensock_;
};
Start
  1. 那么这里小编就压缩一下,将初始化,启动以及释放的工作全部放在Start中
  2. 首先常规套路调用接口创建套接字,然后绑定,监听即可,然后服务器一旦启动要基于死循环所以这里for( ; ; )死循环即可,那么就要调用Accept接收请求,然后如果接收失败,那么continue继续接收,走到下一步就接收成功了,此时得到了Accept的返回值sockfd用于对客户端做出响应
  3. 那么接收成功就使用日志打印信息即可,然后new一个线程数据对象将sockfd和this指针初始化,然后定义线程tid,然后创建线程,传参即可,如果服务器退出,那么调用Close关闭监听文件描述符即可
void Start()
{
    listensock_.Socket();
    listensock_.Bind(port_);
    listensock_.Listen();

    for(;;)
    {
        std::string clientip;
        uint16_t clientport;
        int sockfd = listensock_.Accept(&clientip, &clientport);
        if(sockfd < 0)
            continue;
        lg(Info, "get a new connect, sockfd: %d, %s:%d",sockfd, clientip.c_str(), clientport);
        ThreadData* td = new ThreadData(sockfd, this);

        pthread_t tid;
        pthread_create(&tid, nullptr, ThreadRun, td);
    }

    listensock_.Close();
}
ThreadRun
  1. 那么我们在静态成员函数这个线程函数ThreadRun中,首先服务器只负责接收连接请求,所以服务器不会等待我这个新线程,即服务器不关心新线程的退出信息以及退出状态,那么我们就让新线程执行pthread_dethch线程分离即可,当新线程退出的时候,由系统释放新线程的资源即可
  2. 那么接下来进行类型转换,获取线程数据对象的指针td
  3. 然后定义一个缓冲区,buffer用于接收http请求的报文,尽量定义大一点
  4. 那么下面我们使用recv替代read,recv的前三个参数和read一样,recv的最后一个参数设置为0作用和read一样,阻塞式等待,即recv可以通过设置最后一个参数来决定是否是阻塞式接收,那么recv返回值也和read一样,所以我们使用n接收recv的返回值
  5. 当n大于0的时候,那么就表示recv读取客户端的http请求成功,那么我们约定将http请求当作字符串来看,所以我们在缓冲区的n位置上设置为’’,那么服务器简单的打印一下buffer即可,即本文的服务端的响应仅仅是简单的打印一下消息,并不做任何其它处理
  6. 那么响应完成使用close关闭文件描述符,然后delete释放td,最后返回nullptr即可
static void* ThreadRun(void* args)
{
    pthread_detach(pthread_self());
    ThreadData* td = static_cast<ThreadData*>(args);
    char buffer[10240];
    ssize_t n = recv(td->sockfd, buffer, sizeof(buffer) - 1, 0);
    if(n > 0)
    {
        buffer[n] = 0;
        std::cout << buffer << std::endl;
    }

    close(td->sockfd);
    delete td;

    return nullptr;
}

HttpServer.cc

  1. 所以我们在HttpServer.cc中进行主要的调用逻辑,那么我们期望调用服务器的时候在命令行中接收服务器要绑定的端口号,所以这里我们给main函数带参,然后获取端口号即可,接下来使用智能指针unique_ptr管理new的服务器,然后调用Start启动服务器即可
#include 
#include 
#include 
#include "HttpServer.hpp"


int main(int args, char* argv[])
{
    if(args != 2)
    {
        exit(1);
    }
    uint16_t port = std::stoi(argv[1]);
    
    std::unique_ptr<HttpServer> svr(new HttpServer(port));
    svr->Start();

    return 0;
}

五、测试

  1. 所以我们将服务器启动,并且我们将浏览器当作客户端观察服务器是否可以接收并且打印http请求,那么我们启动服务器,然后拿出浏览器输入小编云服务器的IP地址和httpserver服务器绑定的端口号8080,如下无误
  2. 并且观察Fiddler Classic也确实抓包成功
  3. 那么我们如下观察打印的http请求,符合http请求的格式,无误,测试成功

六、源代码

makefile

httpserver:HttpServer.cc
	g++ -o $@ $^ -std=c++11 -pthread

.PHONY:clean
clean:
	rm -f httpserver

HttpServer.hpp

#pragma once

#include 
#include 
#include "Log.hpp"
#include "Socket.hpp"

static const int defaultport = 8080;

class HttpServer;

class ThreadData
{
public:
    ThreadData(int fd, HttpServer* s)
        : sockfd(fd)
        , svr(s)
    {}
public:
    int sockfd;
    HttpServer* svr;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = defaultport)
        : port_(port)
    {}

    void Start()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();

        for(;;)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if(sockfd < 0)
                continue;
            lg(Info, "get a new connect, sockfd: %d, %s:%d",sockfd, clientip.c_str(), clientport);
            ThreadData* td = new ThreadData(sockfd, this);

            pthread_t tid;
            pthread_create(&tid, nullptr, ThreadRun, td);
        }

        listensock_.Close();
    }

    static void* ThreadRun(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        char buffer[10240];
        ssize_t n = recv(td->sockfd, buffer, sizeof(buffer) - 1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            std::cout << buffer << std::endl;
        }

        close(td->sockfd);
        delete td;

        return nullptr;
    }

    ~HttpServer()
    {}
private:
    uint16_t port_;
    Sock listensock_;
};

HttpServer.cc

#include 
#include 
#include 
#include "HttpServer.hpp"



int main(int args, char* argv[])
{
    if(args != 2)
    {
        exit(1);
    }
    uint16_t port = std::stoi(argv[1]);
    
    std::unique_ptr<HttpServer> svr(new HttpServer(port));
    svr->Start();

    return 0;
}

Sock.hpp

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "Log.hpp"


const int backlog = 10;

enum{
    SocketErr = 1,
    BindErr,
    ListenErr,
};


class Sock
{
public:
    Sock()
    {}

    void Socket()
    {
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if(sockfd_ < 0)
        {
            lg(Fatal, "socket error, %s : %d", strerror(errno), errno);
            exit(SocketErr);
        }
    }

    void Bind(uint16_t port)
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;
        socklen_t len = sizeof(local);

        if(bind(sockfd_, (struct sockaddr*)&local, len) < 0)
        {
            lg(Fatal, "bind error, %s : %d", strerror(errno), errno);
            exit(BindErr);            
        }
    }

    void Listen()
    {
        if(listen(sockfd_, backlog) < 0)
        {
            lg(Fatal, "listen error, %s : %d", strerror(errno), errno);
            exit(ListenErr);
        }
    }

    int Accept(std::string* clientip, uint16_t* clientport)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);

        int newfd = accept(sockfd_, (struct sockaddr*)&peer, &len);
        if(newfd < 0)
        {
            lg(Warning, "accept error, %s : %d", strerror(errno), errno);
            return -1;
        }
        
        char ipstr[128];
        inet_ntop(AF_INET, &(peer.sin_addr), ipstr, sizeof(ipstr));
        *clientip = ipstr;
        *clientport = ntohs(peer.sin_port);

        return newfd;
    }
    
    bool Connect(const std::string& serverip, uint16_t serverport)
    {
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        peer.sin_family = AF_INET;
        peer.sin_port = htons(serverport);
        inet_pton(AF_INET, serverip.c_str(), &(peer.sin_addr));
        socklen_t len = sizeof(peer);

        int n = connect(sockfd_, (struct sockaddr*)&peer, len);
        if(n == -1)
        {
            std::cerr << "connect to " << serverip << ':' << serverport << "error" << std::endl;
            return false;
        }

        return true;
    }

    void Close()
    {
        if(sockfd_ > 0)
        {
            close(sockfd_);
        }
    }

    int Fd()
    {
        return sockfd_;
    }
    
    ~Sock()
    {}
private:
    int sockfd_;
};

Log.hpp

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SIZE 1024

#define Info   0
#define Debug  1
#define Warning 2
#define Error  3
#define Fatal  4

#define Screen 1     //输出到屏幕上
#define Onefile 2    //输出到一个文件中
#define Classfile 3  //根据事件等级输出到不同的文件中

#define LogFile "log.txt" //日志名称


class Log
{
public:
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }

    void Enable(int method) //改变日志打印方式
    {
        printMethod = method;
    }

    ~Log()
    {}

    std::string levelToString(int level)
    {
        switch(level)
        {
            case Info:
                return "Info";
            case Debug:
                return "Debug";
            case Warning:
                return "Warning";
            case Error:
                return "Error";
            case Fatal:
                return "Fatal";
            default:
                return "";
        }
    }

    void operator()(int level, const char* format, ...)
    {
        //默认部分 = 日志等级 + 日志时间
        time_t t = time(nullptr);
        struct tm* ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(), 
        ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday, 
        ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        char logtxt[2 * SIZE];
        snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);

        printLog(level, logtxt);
    }

    void printLog(int level, const std::string& logtxt)
    {
        switch(printMethod)
        {
            case Screen:
                std::cout << logtxt << std::endl;
                break;
            case Onefile:
                printOneFile(LogFile, logtxt);
                break;
            case Classfile:
                printClassFile(level, logtxt);
                break;
            default:
                break;
        }
    }

    void printOneFile(const std::string& logname, const std::string& logtxt)
    {
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if(fd < 0)
            return;
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }

    void printClassFile(int level, const std::string& logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level);

        printOneFile(filename, logtxt);
    }


private:
    int printMethod;
    std::string path;
};

Log lg;


总结

以上就是今天的博客内容啦,希望对读者朋友们有帮助
水滴石穿,坚持就是胜利,读者朋友们可以点个关注
点赞收藏加关注,找到小编不迷路!

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

搜索文章

Tags

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