跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++大前端

Linux 网络编程实战:基于 C++ 实现 JSON+HTTP Web 计算器服务器

深入讲解 C++ 网络编程核心,涵盖 JSON 序列化库 nlohmann/json 的使用与原理,以及 HTTP 协议报文解析细节。通过从零构建一个支持 GET 静态资源与 POST 计算请求的 Web 服务器,演示了 Socket 封装、线程池任务调度及业务逻辑处理流程。适合希望掌握底层网络通信机制的开发者参考。

未来可期发布于 2026/3/22更新于 2026/6/1917 浏览
Linux 网络编程实战:基于 C++ 实现 JSON+HTTP Web 计算器服务器

Linux 网络编程实战:基于 C++ 实现 JSON+HTTP Web 计算器服务器

引入

在之前的学习中,我们了解了序列化与反序列化的概念。对于使用 TCP 协议进行通信的双方,由于 TCP 是面向字节流的,在发送数据之前,通常需要定义一种结构化的数据来描述传输内容。在 C++ 中,这种结构化数据通常表现为对象或结构体。然而,我们不能直接将结构体内存中对应的字节原样发送到另一端,因为直接传递内存字节会引发字节序和结构体内存对齐的问题。

因此,我们需要借助序列化。序列化是指将结构化的数据按照预定的规则转换为连续的字节流。其主要目的是屏蔽平台差异,使得位于不同平台的进程能够以统一的方式解析该字节流。文本序列化直观、可读性高,而二进制序列化传输体积更小。在实际开发中,我们通常不需要从头实现序列化,可以使用成熟的第三方库来完成这项工作。本文将介绍的第一个主题——JSON,就是一种广泛应用的文本序列化格式。

JSON 详解

JSON(JavaScript Object Notation)是一种轻量级、基于文本、人类可读的数据交换格式。它源于 JavaScript,但能跨语言解析。JSON 支持整型、浮点型、布尔型、字符串、对象及数组等基本数据类型。

nlohmann/json 库的使用

在 C++ 中,常用的 JSON 库包括 json.hpp(即 nlohmann/json)。它是一个单头文件库,无需编译,只需将其包含到项目中即可。

初始化与操作

json 类的定义位于 nlohmann 命名空间内。创建 json 对象主要有两种方式:

  1. 列表初始化:利用 C++11 特性,通过构造函数传递键值对。
#include "json.hpp"
#include <iostream>
using json = nlohmann::json;

int main() {
    json j = {{"name", "WZ"}, {"age", 20}, {"gender", "girl"}};
    std::cout << j.dump() << std::endl;
    return 0;
}
  1. 赋值运算符:更推荐的方式,符合 C++ 标准库容器习惯。
json j;
j["name"] = "wz";
j["age"] = 20;
j["gender"] = "girl";
序列化与反序列化

json 类提供了 dump() 成员函数用于序列化,返回 std::string。若不传参数,生成紧凑格式;若传入整数,则按指定空格数格式化输出。

反序列化使用静态成员函数 parse()。C++11 引入了原始字符串字面量 R"()" 语法,方便处理包含特殊字符的 JSON 字符串。

std::string s = R"({"name":"WZ","age":18})";
json j = json::parse(s);

原理简析

json.hpp 内部维护一个 json 类,核心成员包括类型变量与联合体形式的值变量。联合体设计使得同一时刻只能表示一种数据类型。构造函数根据输入决定类型,例如接收 std::initializer_list<std::pair> 时初始化为对象,接收 std::initializer_list<json> 时初始化为数组。

重载的 operator[] 实现了灵活的访问接口:接收 string 参数处理对象,接收 size_t 参数处理数组。同时支持隐式类型转换,如 int age = j["age"]。

HTTP 协议基础

HTTP 作为应用层协议,定义了客户端与服务端交互的规则。其本质是对请求与响应报文的格式约束。

URL 与域名解析

URL(Uniform Resource Locator)由协议、域名、端口、路径等组成。浏览器输入网址后,需先通过 DNS 解析将域名转换为 IP 地址,才能建立 TCP 连接。

HTTP 报文结构

HTTP 是文本协议,请求报文包含请求行、请求头、空行和可选的请求正文。响应报文结构类似,包含响应行、响应头、空行和响应正文。

请求方法

常见的请求方法有 GET 和 POST。GET 用于获取资源,通常不带请求正文;POST 用于提交数据,携带请求正文。其他方法如 PUT、DELETE 等也可通过 POST 映射到虚拟路径实现。

状态码
  • 2xx: 成功,如 200 OK。
  • 3xx: 重定向,如 301、302。
  • 4xx: 客户端错误,如 400 Bad Request、404 Not Found。
  • 5xx: 服务器错误,如 500 Internal Server Error。

Web 服务器实现

基于上述理论,我们使用 C++ 实现一个简单的 Web 服务器,支持静态资源访问和简单的计算功能。

架构设计

服务器整体框架遵循固定模式:创建监听套接字,绑定 IP 与端口,进入监听状态。为了解耦连接接收与业务处理,引入线程池管理任务。

Socket 封装

我们将系统接口封装为 sock 类,管理文件描述符生命周期,提供 socket、bind、listen、accept 等方法,并集成日志模块。

Httpserver 类

Httpserver 类维护 sock 对象、IP、端口及监听标志。init 函数负责创建和绑定套接字,start 函数启动监听并进入循环接受连接。

class Httpserver {
public:
    Httpserver(std::string _ip = "0.0.0.0", uint16_t _port = 80)
        : ip(_ip), port(_port), islistening(false) {}
    
    void init() {
        listen_socket.socket();
        listen_socket.bind(ip, port);
    }

    void start() {
        listen_socket.listen();
        if (islistening) return;
        islistening = true;
        threadpool& tp = threadpool::getinstance();
        tp.start();
        struct sockaddr_in client;
        socklen_t client_len = sizeof(client);
        while (islistening) {
            size_t client_fd = listen_socket.accept(&client, &client_len);
            Task t(client_fd);
            tp.push(t);
        }
    }
private:
    uint16_t port;
    std::string ip;
    sock listen_socket;
    bool islistening;
};

通信处理

读取请求

TCP 是面向字节流的,需要依据 HTTP 报文格式判断是否读取完整。HTTP 请求头结束于连续的两个 CRLF(\r\n\r\n)。我们封装 Get_HttpRequest 函数,循环读取直到找到分隔符,并根据 Content-Length 处理请求正文。

解析请求

定义 Http_Request 结构体存储解析后的字段。Deserialization 函数将请求行和请求头分割存入哈希表。

class Http_Request {
public:
    std::unordered_map<std::string, std::string> headers;
    std::string text, method, url, http_version;

    bool Deserialization(std::string& head) {
        // 分割请求头和请求行
        // ... 省略具体分割逻辑 ...
        // 使用 stringstream 解析请求行
        std::stringstream ss(first_line);
        ss >> method >> url >> http_version;
        return true;
    }
};
业务分发

根据 method 字段调用不同的处理函数:

  • GET 请求:处理静态资源。根据 URL 拼接文件路径,查找文件后缀确定 MIME 类型,读取文件内容构建响应。
  • POST 请求:处理动态业务。本例实现了一个计算器,解析请求体中的键值对(a, op, b),执行计算并返回结果。
void run() {
    Http_Request hr;
    if (!Get_HttpRequest(socketfd, hr)) {
        close(socketfd); return;
    }
    std::string res;
    if (hr.method == "GET") {
        res = Http_Get_Handler(hr);
    } else if (hr.method == "POST") {
        res = Http_Post_Handler(hr);
    } else {
        close(socketfd); return;
    }
    send(socketfd, res.c_str(), res.size(), 0);
    close(socketfd);
}

关键代码细节

静态资源处理

Http_Get_Handler 首先判断 URL 是否为根目录,若是则默认返回 index.html。否则拼接路径读取文件。若文件不存在,返回 404 页面。

std::string Http_Get_Handler(Http_Request& hr) {
    std::string file_path;
    if (hr.url == "/" || hr.url == "/index.html") {
        file_path = path + "/index.html";
    } else {
        file_path = path + hr.url;
    }
    std::string body = read_file(file_path);
    // 构建响应报文...
    return res;
}
计算器逻辑

Http_Post_Handler 解析请求体,提取 a, op, b 三个参数。注意处理 URL 编码(如 %2B 转 +)。执行计算后构建 HTML 响应。

bool process_calculation(std::unordered_map<std::string, std::string>& val, int& result) {
    int a = std::stoi(val["a"]);
    int b = std::stoi(val["b"]);
    std::string op = val["op"];
    // 解码运算符
    if (op == "%2B") op = "+"; // ...
    switch (op[0]) {
        case '+': result = a + b; break;
        case '-': result = a - b; break;
        case '*': result = a * b; break;
        case '/': 
            if (b == 0) return false;
            result = a / b; break;
    }
    return true;
}

结语

本文从 JSON 序列化原理入手,深入讲解了 HTTP 协议细节,并通过实战代码演示了如何从零构建一个支持多线程的 C++ Web 服务器。掌握这些底层机制,有助于更好地理解网络通信的本质。

目录

  1. Linux 网络编程实战:基于 C++ 实现 JSON+HTTP Web 计算器服务器
  2. 引入
  3. JSON 详解
  4. nlohmann/json 库的使用
  5. 初始化与操作
  6. 序列化与反序列化
  7. 原理简析
  8. HTTP 协议基础
  9. URL 与域名解析
  10. HTTP 报文结构
  11. 请求方法
  12. 状态码
  13. Web 服务器实现
  14. 架构设计
  15. Socket 封装
  16. Httpserver 类
  17. 通信处理
  18. 读取请求
  19. 解析请求
  20. 业务分发
  21. 关键代码细节
  22. 静态资源处理
  23. 计算器逻辑
  24. 结语
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 人工智能与机器学习核心面试题及解析
  • 基于无人机的多模态目标检测:高多样性基准与基线方法
  • 前端流式输出技术:原理与实战指南
  • 大模型在信用卡行业的应用探索
  • GitHub 开源:30+ 个 OpenClaw 真实使用场景与落地实践
  • 数据结构:排序算法详解(下)
  • Java 调用 UniHttp 接口参数乱序导致百度 SN 校验失败解决方案
  • 工程师转型量化金融:角色定位、技能提升与面试指南
  • Spring Boot 2.7.x 升级 Logback 至 1.3.x 及以上版本的解决方案
  • Python 量化数据接口指南:baostock 获取分钟级 K 线数据
  • Stable Diffusion 文生图基础详解与参数配置
  • FPGA 数字运算与控制:浮点数实现与 PID 算法
  • 软件工程范式演进:低代码技术逻辑与全栈化趋势
  • 2026 年 3 月全球 AI 前沿动态与行业深度洞察
  • 人类与 AI 的意群阅读机制及英语学习技巧
  • C++ 继承进阶:友元、静态成员与菱形继承底层逻辑
  • 在安卓设备使用 llama.cpp 部署 Llava 多模态模型
  • 基于 LangGraph 构建模块化 Skills 型 AI Agent
  • 前端网页开发基础教程:HTML、CSS 与 JavaScript
  • MogFace 人脸检测部署:合影人数统计零代码实战

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online