最新资讯

  • http实现服务器与浏览器通信

http实现服务器与浏览器通信

2026-01-28 20:55:38 栏目:最新资讯 4 阅读

一、浏览器访问 Web 服务器的 HTTP 通信全流程

包含 DNS 解析、TCP 连接、HTTP 收发、连接管理 4 个核心环节,我分步骤拆解(清晰到每一步):

步骤 1:DNS 解析(浏览器先找到服务器的 IP)

  • 浏览器输入www.baidu.com(域名),但网络通信需要IP 地址
  • 浏览器向DNS 服务器发起请求,查询www.baidu.com对应的 IP(比如180.101.50.242);
  • DNS 返回该域名的 IP,浏览器拿到目标服务器的 IP 后,准备建立连接。

步骤 2:建立 TCP 连接(三次握手)

  • 浏览器调用connect(),向服务器的80 端口(HTTP 默认端口)发起 TCP 三次握手:
    1. 浏览器发SYN → 2. 服务器回SYN+ACK → 3. 浏览器回ACK
  • 握手完成后,浏览器与服务器建立可靠的 TCP 连接(图中 “tcp 连接”)。

步骤 3:发送 HTTP 请求报文

  • 浏览器通过已建立的 TCP 连接,向服务器发送HTTP 请求报文(比如GET /index.html HTTP/1.1),包含请求方法、资源路径、协议版本等信息。

GET http://www.baidu.com/index.html HTTP/1.0  → 请求行
User-Agent: Wget/1.12 (linux-gnu)             → 请求头1
Host: www.baidu.com                          → 请求头2
Connection: close                            → 请求头3

①请求行(第 1 行,HTTP 请求的核心指令)

请求行由 「请求方法」+「请求 URL」+「协议版本」 三部分组成,每部分都有明确作用:

  1. 请求方法(GET)
    • 是客户端对服务器的 “操作指令”,图中GET表示 “读取服务器资源”(只读、不修改服务器数据);
    • 不同方法对应不同操作(比如 POST 是 “提交数据”,PUT 是 “上传资源”)。
  2. 请求 URL(http://www.baidu.com/index.html)
    • 明确要访问的服务器资源路径,这里是百度首页的index.html文件。
  3. 协议版本(HTTP/1.0)
    • 表示使用的 HTTP 协议版本,不同版本支持的特性不同(比如 HTTP/1.0 默认短连接,HTTP/1.1 默认长连接)。

②请求头(第 2-4 行,传递附加信息)

请求头是 “键值对” 格式(键: 值),用来告诉服务器请求的附加信息,图中这几个头是高频必知的:

  1. User-Agent: Wget/1.12 (linux-gnu)
    • 告诉服务器 “客户端的身份”:这里是 Linux 系统下的Wget工具(一种命令行下载工具);
    • 服务器可以通过这个头识别客户端类型(比如是浏览器、手机 APP 还是爬虫)。
  2. Host: www.baidu.com
    • 告诉服务器 “目标域名”:因为一台服务器可能绑定多个域名,这个头用来指定要访问的具体域名;
    • 是 HTTP/1.1 的必选头(HTTP/1.0 可选,但实际也会传)。
  3. Connection: close
    • 告诉服务器 “本次请求用短连接”:HTTP/1.0 默认是短连接,请求完成后服务器会关闭 TCP 连接;
    • 如果是Connection: keep-alive,就是长连接(HTTP/1.1 默认),连接会保留供后续请求复用。

③补充:GET 请求的特点(结合示例)

图中是GET请求,它的核心特点是:

  • 无请求体:因为是 “读取资源”,不需要向服务器提交数据,所以请求只有 “请求行 + 请求头”;
  • 数据在 URL 中:如果要传参数,会拼接在 URL 后面(比如index.html?name=test);
  • 幂等性:多次调用GET请求,不会修改服务器的状态(比如多次请求index.html,服务器数据不会变)。

步骤 4:服务器返回 HTTP 应答报文

  • 服务器接收请求后,处理请求(比如读取index.html文件),通过 TCP 连接向浏览器返回HTTP 应答报文(包含状态码、响应头、响应体),报文实力如下。

一、状态行(第 1 行)

HTTP/1.0 200 OK

  • HTTP/1.0:使用的 HTTP 协议版本;
  • 200状态码,表示 “请求成功”(是最常见的成功状态码);
  • OK:状态码的描述文本,与200对应。

二、响应头(第 2-6 行,服务器返回的附加信息)

  1. Server: BWS/1.0
    • 服务器标识:表示这是百度的 BWS 服务器(Baidu Web Server)。
  2. Content-Length: 8024
    • 响应体的字节数:告诉客户端,后续返回的资源(比如网页)大小是 8024 字节。
  3. Content-Type: text/html;charset=gbk
    • 响应体的类型和编码:
      • text/html:资源是 HTML 网页;
      • charset=gbk:网页内容的编码格式是 GBK。
  4. Set-Cookie: BAIDUID=...
    • 服务器向客户端设置 Cookie:用于身份识别、会话保持(比如登录状态),后续客户端请求会自动携带这个 Cookie。
  5. Via: 1.0 localhost (squid/3.0.STABLE18)
    • 代理信息:表示请求经过了本地的 Squid 代理服务器(版本 3.0)转发。

HTTP 应答报文中的「状态码分类与含义」

步骤 5:连接管理(短连接 / 长连接)

  • 短连接(图中 “close 短连接”):HTTP 1.0 默认是短连接,服务器返回应答后,主动关闭 TCP 连接;
  • 长连接(图中 “长连接”):HTTP 1.1 默认是长连接,服务器返回应答后,TCP 连接不关闭,后续浏览器可复用该连接发送新的 HTTP 请求(减少重复握手的开销)。

总结整个流程

浏览器通过DNS 解析域名→TCP 三次握手建连→发 HTTP 请求→收 HTTP 响应→根据短 / 长连接策略管理 TCP 连接,完成一次 Web 资源的访问。

二、写myhttp.c http服务器让其和浏览器通信 

我们现在写:一个tcp的服务器端,他的业务时和浏览器(客户端)进行通信,所以不用写客户端 只用吧服务器端写好。

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

// 1. 服务器初始化函数:创建套接字+绑定+监听
int socket_init()
{
    // 创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        return -1;
    }

    // 配置服务器地址(IP:127.0.0.1,端口:80)
    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(80);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // 绑定地址
    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
    if (res == -1)
    {
        printf("bind err
");
        return -1;
    }

    // 监听(队列长度5)
    if(listen(sockfd,5) == -1 )
    {
        return -1;
    }

    return sockfd;
}

// 2. 线程处理函数:与客户端通信
void* thread_fun(void* arg)
{
    // 接收客户端套接字描述符
    int *p = (int*)arg;
    int c = *p;
    free(p); // 释放动态分配的内存

    char buff[1024] = {0};
    // 接收客户端数据
    int n = recv(c, buff, 1023, 0);
    if (n <= 0)
    {
        close(c);
        pthread_exit(NULL); // 线程退出
    }

    printf("buff=%s
", buff);
    send(c, "OK", 2, 0); // 回复客户端
    close(c);
    return NULL;
}

// 3. 主函数:接收连接+创建线程
int main()
{
    int sockfd = socket_init();
    if (sockfd == -1)
    {
        exit(1);
    }

    while(1)
    {
        // 接收客户端连接,得到客户端套接字c
        int c = accept(sockfd, NULL, NULL);
        if (c < 0)
        {
            continue;
        }

        // 动态分配内存存c(避免线程间共享栈变量)
        int *p = (int*)malloc(sizeof(int));
        *p = c;
        // 创建线程,执行thread_fun处理该客户端
        pthread_t tid;
        pthread_create(&tid, NULL, thread_fun, (void*)p);
    }

    exit(1);
}

核心逻辑讲解

  1. socket_init():服务器初始化

    • 完成socket(创建 TCP 套接字)→ bind(绑定 127.0.0.1:80)→ listen(开启监听),返回监听套接字 sockfd
  2. main():主线程接收连接 + 创建工作线程

    • 循环调用accept接收客户端连接,得到客户端套接字c
    • 动态分配内存存储c(避免线程共享栈变量),通过pthread_create创建新线程,将c传给thread_fun
  3. thread_fun():工作线程处理客户端通信

    • 接收c,释放内存;
    • 通过recv接收客户端数据,send回复 “OK”;
    • 通信完成后关闭c,线程退出。

多线程并发的特点

  • 相比多进程,线程更轻量(资源开销小);
  • 需注意内存管理(用malloc传递c,避免栈变量被多线程共享);
  • 实现 “一个客户端对应一个线程” 的并发服务,适合高并发场景。

测试

①测试准备(终端操作)

  1. 编译代码:用gcc -o myhttp myhttp.c -lpthread编译服务器代码(-lpthread是链接线程库)。
  2. 首次启动失败:直接运行./myhttp提示bind err—— 因为服务器绑定的是80 端口(HTTP 默认端口),普通用户无权限使用 1024 以下端口。
  3. 提权启动:用sudo su切换到 root 用户,再运行./myhttp,服务器成功启动(获得 80 端口的使用权限)。

②通信测试(浏览器 + 服务器交互)

  1. 浏览器发起请求:在浏览器中访问127.0.0.1/index.html(本地服务器),浏览器自动发送HTTP GET 请求(包含请求行、请求头,如GET /index.html HTTP/1.1User-Agent等)。
  2. 服务器接收并处理:服务器的accept接收到浏览器连接,创建线程执行thread_fun
    • 通过recv接收浏览器的 HTTP 请求,终端打印请求内容(buff=GET /index.html...);
    • 调用send回复 “OK”。
  3. 浏览器接收回复:浏览器显示服务器返回的 “OK”,完成一次 HTTP 通信。

③核心验证点

  • 验证了 “多线程服务器 + 80 端口权限 + HTTP 请求处理” 的流程;
  • 解决了 “普通用户无法绑定低端口” 的问题(通过 root 提权);
  • 实现了浏览器与服务器的 HTTP 请求 - 响应交互。

解析模块:

解析拿出请求方法

三、在原多线程 TCP 服务器基础上,扩展为简易 HTTP 文件服务器

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

// 你的代码里定义的文件根目录,和截图一致
#define PATH "/home/stu/c2305/day22"

// 解析HTTP请求行,提取请求的文件名 如 GET /index.html HTTP/1.1 -> /index.html
char* get_filename(char buff[])
{
    char* ptr = NULL;
    char* s = strtok_r(buff, " ", &ptr); // 分割出GET/POST
    if(s == NULL)
    {
        return NULL;
    }
    s = strtok_r(NULL, " ", &ptr); // 分割出请求的文件路径
    return s;
}

// 服务器初始化:创建socket、绑定、监听
int socket_init()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
        perror("socket err");
        return -1;
    }

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(80);  // HTTP默认80端口
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res == -1)
    {
        perror("bind err");
        return -1;
    }

    if(listen(sockfd,5) == -1)
    {
        perror("listen err");
        return -1;
    }
    return sockfd;
}

// 线程处理函数:处理客户端HTTP请求+返回文件
void* thread_fun(void* arg)
{
    int c = *(int*)arg;
    free(arg); // 释放malloc的堆内存

    char buff[1024] = {0};
    int n = recv(c,buff,1023,0);
    if(n <= 0)
    {
        close(c);
        pthread_exit(NULL);
    }
    printf("收到客户端请求:
%s
",buff);

    // 1. 解析请求的文件名
    char* filename = get_filename(buff);
    if(filename == NULL)
    {
        close(c);
        pthread_exit(NULL);
    }

    // 2. 拼接完整文件路径
    char file_path[256] = {0};
    strcpy(file_path,PATH);
    // 如果访问根目录 / ,默认打开index.html
    if(strcmp(filename,"/") == 0)
    {
        strcat(file_path,"/index.html");
    }
    else
    {
        strcat(file_path,filename);
    }
    printf("要打开的文件路径: %s
",file_path);

    // 3. 以只读方式打开文件
    int fd = open(file_path,O_RDONLY);
    if(fd == -1)
    {
        // 文件打开失败,返回HTTP 404响应
        char err_msg[512] = "HTTP/1.1 404 Not Found
Content-Type:text/html;charset=utf-8

404 页面不存在

"; send(c,err_msg,strlen(err_msg),0); close(c); pthread_exit(NULL); } // 4. 获取文件大小 struct stat st; fstat(fd,&st); int file_size = st.st_size; // 5. 拼接HTTP 200成功响应头 char head_msg[512] = {0}; sprintf(head_msg,"HTTP/1.1 200 OK Content-Length:%d Content-Type:text/html;charset=utf-8 ",file_size); send(c,head_msg,strlen(head_msg),0); // 6. 循环读取文件内容并发送给浏览器 char file_buff[1024] = {0}; int read_len = 0; while((read_len = read(fd,file_buff,1024)) > 0) { send(c,file_buff,read_len,0); memset(file_buff,0,sizeof(file_buff)); } // 收尾:关闭文件、关闭客户端套接字 close(fd); close(c); pthread_exit(NULL); } int main() { int sockfd = socket_init(); if(sockfd == -1) { exit(1); } printf("HTTP服务器启动成功,监听 127.0.0.1:80 ... "); pthread_attr_t attr; pthread_attr_init(&attr); // 设置线程分离属性:线程退出后自动释放资源,解决内存泄漏! pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); while(1) { int c = accept(sockfd,NULL,NULL); if(c < 0) { continue; } printf("有客户端连接成功! "); int* p = (int*)malloc(sizeof(int)); *p = c; pthread_t tid; // 创建分离属性的线程 pthread_create(&tid,&attr,thread_fun,(void*)p); } pthread_attr_destroy(&attr); close(sockfd); exit(0); }

一、核心功能升级:从 “回复固定 OK” 到 “返回文件”

原代码只是接收请求后回复 “OK”,这段代码新增了HTTP 请求解析 + 文件路径拼接的逻辑,目标是:浏览器访问127.0.0.1/index.html → 服务器解析出请求的文件是/index.html → 拼接本地路径/home/stu/c2305/day22/index.html → 读取该文件并返回给浏览器。

二、逐段解析新增逻辑

1. get_filename(char buff[]):解析 HTTP 请求中的文件路径

作用:从浏览器发送的 HTTP 请求(存在buff中)里,提取要访问的文件路径(比如从GET /index.html HTTP/1.1中提取/index.html

char* get_filename(char buff[])
{
    char* ptr = NULL;
    // 第一步:用空格分割请求行,拿到第一个字段(请求方法,比如GET)
    char* s = strtok_r(buff, " ", &ptr);
    if (s == NULL) { return NULL; }
    printf("请求方法: %s
", s);

    // 第二步:分割得到第二个字段(文件路径,比如/index.html)
    s = strtok_r(NULL, " ", &ptr);
    return s; // 返回解析出的文件路径
}
  • 示例:若buffGET /index.html HTTP/1.1strtok_r第一次分割出GET,第二次分割出/index.html,最终返回/index.html
2. 线程函数thread_fun:新增文件路径拼接逻辑

在原 “接收请求” 后,新增了解析路径、拼接本地目录的步骤:

// 1. 解析HTTP请求中的文件路径
char* filename = get_filename(buff);
if (filename == NULL ) { break; }

// 2. 拼接本地文件的完整路径
char path[256] = {PATH}; // PATH是宏定义的本地目录:/home/stu/c2305/day22
// 处理根路径请求(比如浏览器访问127.0.0.1,filename是"/")
if ( strcmp(filename,"/") == 0 )
{
    filename = "/index.html"; // 默认返回index.html
}
strcat(path,filename); // 拼接成完整路径:比如/home/stu/c2305/day22/index.html
printf("path:%s
",path);
  • 示例:若解析出filename=/index.html,拼接后path/home/stu/c2305/day22/index.html,后续会打开这个文件并返回给浏览器。

四、我们现在请求服务器查看一张图片

#include 
#include 
#include 
#include 
#include    // 网络套接字核心头文件 socket/bind/listen/accept/recv/send
#include    // 网络地址结构体 sockaddr_in 网络字节序转换函数
#include     // 地址转换相关函数
#include       // 线程库头文件 pthread_create/pthread_exit
#include         // 文件打开 open 函数头文件
#include     // 系统类型定义

// 服务器存放网页文件的根目录,和你的截图一致,不要修改
#define PATH "/home/stu/c2305/day22"

/**************************************************************************
函数名:get_filename
函数功能:解析浏览器发送的HTTP请求报文,提取请求的文件路径
参数:buff 接收客户端请求数据的缓冲区
返回值:成功返回请求的文件路径 如:/index.html  失败返回NULL
**************************************************************************/
char* get_filename(char buff[])
{
    char* ptr = NULL;
    // 第一次分割,获取请求方法 GET/POST
    char* s = strtok_r(buff, " ", &ptr);
    if(s == NULL) // 分割失败,返回NULL
    {
        return NULL;
    }
    // 第二次分割,获取请求的文件路径 核心提取逻辑
    s = strtok_r(NULL, " ", &ptr);
    return s;
}

/**************************************************************************
函数名:socket_init
函数功能:TCP服务器初始化核心函数,完成 创建套接字-绑定端口-开启监听 三步操作
返回值:成功返回监听套接字描述符  失败返回-1
**************************************************************************/
int socket_init()
{
    // 创建TCP流式套接字 AF_INET:IPv4协议 SOCK_STREAM:TCP协议 0:默认
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd == -1)
    {
        printf("socket err
");
        return -1;
    }

    // 初始化服务器地址结构体
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));          // 清空结构体垃圾值
    saddr.sin_family = AF_INET;              // 地址族:IPv4
    saddr.sin_port = htons(80);              // 绑定HTTP默认端口80,主机序转网络序
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 绑定本地回环地址,仅本机可访问

    // 绑定:将套接字与指定的IP+端口进行绑定
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res == -1)
    {
        printf("bind err
");
        return -1;
    }

    // 监听:开启套接字监听,等待客户端连接,5是半连接队列长度
    if(listen(sockfd,5) == -1)
    {
        return -1;
    }
    return sockfd; // 初始化成功,返回监听套接字
}

/**************************************************************************
函数名:thread_fun
函数功能:线程处理业务函数,每个客户端连接对应一个独立线程
          完成:接收HTTP请求 -> 解析文件路径 -> 打开文件 -> 返回文件给浏览器
参数:arg 主线程传递的客户端套接字描述符地址
返回值:线程退出返回NULL
**************************************************************************/
void* thread_fun(void* arg)
{
    // 接收主线程传递的客户端套接字描述符
    int c = *(int*)arg;
    free(arg);  // 释放malloc申请的堆内存,防止内存泄漏

    // 定义缓冲区接收客户端的HTTP请求数据
    char buff[1024] = {0};
    // 阻塞接收客户端发送的请求数据,成功返回接收字节数,失败/断开返回<=0
    int n = recv(c,buff,1023,0);
    if(n <= 0)  // 接收失败或客户端断开连接
    {
        close(c);          // 关闭客户端套接字
        pthread_exit(NULL); // 线程正常退出
    }
    printf("recv buf=%s
",buff); // 打印收到的HTTP请求报文

    // 1. 解析HTTP请求中要访问的文件路径
    char* filename = get_filename(buff);
    if(filename == NULL) // 解析失败,直接释放资源退出
    {
        close(c);
        pthread_exit(NULL);
    }

    // 2. 拼接要打开的文件完整路径
    char path[256] = {0};
    strcpy(path, PATH);       // 拼接根目录
    if(strcmp(filename, "/") == 0) // 如果访问根目录 / ,默认打开首页index.html
    {
        filename = "/index.html";
    }
    strcat(path, filename);   // 拼接完整文件路径
    printf("path=%s
",path); // 打印拼接后的文件路径

    // ====================== 以下是你截图的核心代码 完整保留 ======================
    // 以只读方式打开拼接好的文件
    int fd = open(path,O_RDONLY);
    if(fd == -1)  // 文件打开失败,直接跳出逻辑
    {
        close(c);
        pthread_exit(NULL);
    }
    // 通过文件偏移量计算文件大小:将光标移到文件末尾,返回的偏移量就是文件总字节数
    int filesize = lseek(fd,0,SEEK_END);
    lseek(fd,0,SEEK_SET);  // 将光标重新移回文件开头,准备读取文件内容

    // 拼接HTTP响应头,严格遵守HTTP协议格式
    char head[256] = {"HTTP/1.1 200 OK
"};  // 状态行:请求成功
    strcat(head,"Server: myhttp
");         // 响应头:服务器标识
    sprintf(head,"%sContent-Length:%d
",head,filesize); // 响应头:告诉浏览器文件大小
    strcat(head,"
");                       // 响应头结束标志:空行(
)
    send(c,head,strlen(head),0);               // 将响应头发送给浏览器

    // 循环读取文件内容,分批次发送给浏览器
    char data[1024] = {0}; // 定义文件读取缓冲区
    int num = 0;
    // 每次读取1024字节,读到内容>0则发送,读完返回0则结束循环
    while((num = read(fd,data,1024))>0)
    {
        send(c,data,num,0); // 将读取的文件内容发送给客户端
    }
    close(fd);  // 文件读取完毕,关闭文件描述符释放资源
    // ====================== 你截图的核心代码 结束 ======================

    close(c);   // 关闭客户端套接字,释放连接资源
    return NULL;
}

/**************************************************************************
主函数:程序入口
功能:初始化服务器 -> 循环接收客户端连接 -> 为每个客户端创建独立线程处理业务
**************************************************************************/
int main()
{
    // 调用初始化函数,获取监听套接字
    int sockfd = socket_init();
    if(sockfd == -1) // 初始化失败,直接退出程序
    {
        exit(1);
    }

    // 设置线程分离属性,解决线程退出后的资源泄漏问题
    pthread_attr_t attr;
    pthread_attr_init(&attr);  // 初始化线程属性
    // 设置分离属性:线程运行结束后,系统自动回收线程资源,无需主线程join
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 死循环,永久监听客户端连接请求
    while(1)
    {
        // 阻塞等待客户端连接,成功返回客户端套接字,失败返回-1
        int c = accept(sockfd,NULL,NULL);
        if(c < 0) // 连接失败,继续等待下一个客户端
        {
            continue;
        }
        // 动态申请堆内存存放客户端套接字,防止线程共享栈变量导致数据错乱
        int *p = (int*)malloc(sizeof(int));
        *p = c;
        pthread_t tid; // 定义线程ID
        // 创建线程处理当前客户端的业务请求
        pthread_create(&tid,&attr,thread_fun,(void*)p);
    }
    close(sockfd); // 关闭监听套接字(实际死循环不会执行到这里)
    exit(0);
}

一、先看【代码整体架构】(3 大核心部分,总分总结构,特别清晰)

整个代码一共分为 3 个核心函数 + 头文件 / 宏定义,执行逻辑是:宏定义/头文件socket_init() 服务器初始化main() 主线程:接连接+创线程thread_fun() 子线程:处理业务+返回文件get_filename() 工具函数:解析请求所有功能各司其职,主线程只做「接待」,子线程只做「干活」,分工明确。


二、第一部分:头文件 + 宏定义(程序的基础依赖)

#include 
#include 
#include 
#include 
#include    // 网络核心函数:socket/bind/listen/accept/recv/send
#include    // 网络地址结构体 sockaddr_in + 字节序转换 htons
#include     // 地址转换 inet_addr
#include       // 线程库:pthread_create 创建线程、pthread_exit 退出线程
#include         // 文件操作:open 打开文件
#include     // 系统基础类型定义

#define PATH "/home/stu/c2305/day22"  // 固定宏:你的服务器存放html文件的根目录

✅ 核心说明:

  1. 这些头文件是必加的依赖,少一个都会编译报错;
  2. #define PATH 是你本地存放网页文件的目录,浏览器访问的所有 html 文件,都必须放在这个目录下,否则服务器找不到。

三、第二部分:3 个核心函数 逐函数讲解(重中之重,全部吃透)

✅ 函数 1:char* get_filename(char buff[]) 【工具函数:解析 HTTP 请求】

作用

从浏览器发送的HTTP 请求报文里,提取出你要访问的文件路径。

核心逻辑

浏览器访问 http://127.0.0.1/index.html 时,会给服务器发一段请求数据,格式是:GET /index.html HTTP/1.1 ...

  • 这个函数用 strtok_r空格分割这段字符串;
  • 第一次分割:拿到 GET(请求方法,我们不用管);
  • 第二次分割:拿到 /index.html(核心!这就是要打开的文件路径);
关键点
  • 返回值:成功返回文件路径,失败返回 NULL;
  • 特殊情况:如果浏览器只访问 http://127.0.0.1,分割出来的是 /,后续会自动替换成 /index.html(访问首页)。

✅ 函数 2:int socket_init() 【核心初始化函数:TCP 服务器三件套】

作用

一站式完成 TCP 服务器的初始化工作,执行 TCP 服务器的经典三步操作,成功返回「监听套接字」,失败返回 - 1,是所有网络通信的基础。

内部执行的 3 个核心步骤(TCP 服务器必背)
  1. socket():创建 TCP 套接字,得到一个文件描述符sockfd,相当于服务器的「总大门」;
  2. bind():把这个「大门」绑定到 127.0.0.1:80(本地 IP+HTTP 默认 80 端口),从此这个端口就归服务器用了;
  3. listen():开启监听,让服务器的「大门」处于等待状态,等待浏览器来连接,参数5是最多同时等待 5 个未处理的连接。
易错点(面试常问)
  • 运行时报 bind err:因为 80 端口是 Linux 的特权端口(1024 以下),普通用户没权限绑定,必须用 sudo ./myhttp 运行;
  • 返回 - 1 都是初始化失败,程序直接退出。

✅ 函数 3:void* thread_fun(void* arg) 【核心业务函数:子线程干活的核心】

作用

这是整个程序的业务核心每一个浏览器连接,都会创建一个独立的这个线程,所有和浏览器的「通信、解析请求、读文件、返回文件」的工作,都在这个函数里完成。

给谁干活?

参数arg是主线程传过来的「客户端套接字 c」,这个c是浏览器和服务器的专属通信通道,每个浏览器的c都不一样,互不干扰。

内部完整执行流程(按顺序,和代码一一对应,必记)

plaintext

1. 接收主线程传的客户端套接字c → free释放堆内存(防止内存泄漏)
2. recv(c, buff, ...) 阻塞接收浏览器发来的HTTP请求数据
3. 如果接收失败/浏览器断开 → 关闭c,线程退出
4. 调用get_filename解析出要访问的文件路径
5. 拼接完整文件路径:根目录PATH + 文件路径 → 比如 /home/stu/c2305/day22/index.html
6. open(path, O_RDONLY) 以只读方式打开这个文件
7. 用lseek计算文件大小:光标移到文件末尾得到总字节数 → 光标移回开头准备读取
8. 拼接HTTP响应头:按HTTP协议规范,告诉浏览器「请求成功,接下来给你发文件」
9. send发送响应头 → 循环read读文件内容 + send发送给浏览器
10. 读完文件后,close关闭文件、close关闭客户端套接字 → 线程完成工作,自动退出

补充的「打开文件、lseek 算大小、拼响应头、读文件发送」的代码,完整放在这个函数里,这部分是HTTP 服务器的核心能力:从「只返回 OK」升级为「返回真实网页文件」。


四、第三部分:main() 主函数 【程序入口 + 总指挥,最核心的调度逻辑】

这是程序的入口,所有代码从这里开始执行,主线程只做一件事:无限循环接收连接,为每个连接创建独立线程,什么业务都不处理,保证永不卡顿,是多线程并发的精髓!

main 函数完整执行流程(逐行逻辑,必背)

  1. 调用 socket_init() 初始化服务器,拿到监听套接字sockfd,初始化失败则直接退出程序;
  2. 设置线程分离属性:这是解决内存泄漏的关键!子线程干完活退出后,系统会自动回收线程资源,不用主线程操心;
  3. 进入 while(1) 死循环:服务器永久运行,永不退出,一直等待客户端连接;
  4. 调用 accept(sockfd, ...) 阻塞等待:有浏览器来连接时,就返回一个「客户端套接字 c」,这个c是和该浏览器的专属通道;
  5. malloc申请堆内存存放c重中之重!面试必考!
    • 为什么不用 &c 直接传?因为c是主线程的栈变量,主线程会立刻回到循环,栈变量的值会被下一个浏览器的连接覆盖,子线程会拿到错误的值;
    • malloc申请的是堆内存,独立不受影响,子线程拿到后free释放即可;
  6. 调用 pthread_create 创建子线程:把堆内存的地址传给子线程函数thread_fun,子线程开始干活,主线程立刻回到accept继续等下一个连接。

核心精髓

主线程 只做「接客」,子线程 只做「干活」,主线程永远不会阻塞在业务逻辑上,可以同时接收无数个浏览器的连接,这就是「多线程并发」!


五、整段代码的【完整运行流程】(从头到尾串一遍,打通任督二脉)

把所有逻辑串起来,一步一步执行,这就是你运行程序后,完整的执行过程,背下来,面试直接说,满分答案

plaintext

1. 编译代码:gcc -o myhttp myhttp.c -lpthread (加-lpthread链接线程库)
2. 运行程序:sudo ./myhttp (sudo提权,绑定80端口成功,服务器启动)
3. 主线程进入死循环,阻塞在accept(),等待浏览器连接
4. 打开浏览器,输入 http://127.0.0.1 访问本机
5. accept()收到连接,返回客户端套接字c → malloc存c → 创建子线程
6. 子线程执行thread_fun:
   - recv接收浏览器的HTTP请求 → get_filename解析出 / → 替换成/index.html
   - 拼接路径 /home/stu/c2305/day22/index.html → open打开这个文件
   - lseek算文件大小 → 拼接HTTP响应头 → send发送响应头
   - 循环read读文件内容,send发送给浏览器
7. 浏览器收到文件内容,渲染出网页页面
8. 子线程close文件、close客户端套接字 → 线程退出,系统自动回收资源
9. 主线程一直卡在accept(),等待下一个浏览器访问,循环往复,永久运行

六、核心知识点总结 + 面试必背考点(全部是你代码里的重点)

✅ 1. 多线程的核心优势

一个线程处理一个客户端,支持并发访问:多个浏览器可以同时访问你的服务器,互不影响,效率远高于单线程。

✅ 2. 两个内存泄漏的解决方案(代码里都做了,必记)

  • 堆内存泄漏:用malloc传参,子线程里free释放;
  • 线程资源泄漏:设置线程分离属性,线程退出自动回收资源。

✅ 3. TCP 和 HTTP 的关系(你这个代码完美体现)

  • TCP 是传输层协议:负责建立可靠的连接、收发数据,是底层通信保障;
  • HTTP 是应用层协议:是 TCP 之上的规则,规定了请求和响应的格式;
  • 你的代码本质是:基于 TCP 协议实现了 HTTP 协议的核心规则

✅ 4. 关键函数分类记忆

  • TCP 服务器四件套:socketbindlistenaccept
  • 数据收发:recv 收数据、send 发数据
  • 文件操作:open 打开、read 读取、close 关闭、lseek 计算大小
  • 线程操作:pthread_create 创建、pthread_exit 退出

最后补充:运行前的准备工作(保证一次成功)

在你的目录 /home/stu/c2305/day22 下,创建一个测试的index.html文件,随便写内容就行:

cd /home/stu/c2305/day22
touch index.html
echo "

我的HTTP服务器运行成功!

这是我的第一个网页

" > index.html

写完后浏览器访问 http://127.0.0.1,就能看到页面了!

测试:

一、测试过程(步骤清晰)

  1. 准备工作:在服务器根目录 /home/stu/c2305/day22 下,放入了图片文件 dog2.jpeg(和 index.html 同目录);
  2. 启动服务器:用 sudo ./myhttp 启动服务器(绑定 80 端口);
  3. 浏览器访问:在浏览器中输入 http://127.0.0.1/dog2.jpeg,请求访问该图片;
  4. 服务器处理
    • 接收浏览器的 HTTP 请求(GET /dog2.jpeg HTTP/1.1);
    • 解析出文件路径 /dog2.jpeg,拼接为完整路径 /home/stu/c2305/day22/dog2.jpeg
    • 打开图片文件,计算大小、构造 HTTP 响应头、发送文件内容;
  5. 浏览器渲染:成功接收图片数据,在页面上显示 dog2.jpeg

二、终端日志解析(每一行的含义)

plaintext

buff=GET /dog2.jpeg HTTP/1.1...  # 服务器收到浏览器的HTTP请求,请求方法是GET,目标资源是/dog2.jpeg
请求方法: GET                    # 解析出请求方法为GET
path:/home/stu/c2305/day22/dog2.jpeg  # 拼接后的完整图片路径

这些日志对应代码中的 printf 输出,证明服务器成功解析了请求并定位到了图片文件。

三、核心验证点(服务器的能力升级)

  • 原代码只能返回 HTML 文件,这次测试验证了:服务器支持返回任意静态资源(图片、CSS、JS 等),只要资源在根目录下,浏览器就能正确请求并渲染;
  • 本质原因:HTTP 响应头中的 Content-Length 只负责告诉浏览器「资源大小」,不限制资源类型,浏览器会根据文件后缀自动识别并渲染(如.jpeg会识别为图片)。

四、为什么能成功显示图片?

服务器的处理逻辑对所有静态资源通用

  1. 不管是.html还是.jpeg,服务器都会按「打开文件→计算大小→发响应头→发文件内容」的流程处理;
  2. 浏览器收到数据后,会根据请求的资源后缀(.jpeg),自动以图片格式解析并渲染,无需修改服务器代码。

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

搜索文章

Tags

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