如何使用nlohmann JSON实现TCP套接字读写及JSON与原始数据互转?
使用nlohmann JSON库的两个核心操作:原始数据转JSON与TCP套接字读写
一、将原始数据转换为JSON
原始数据的形式不同,转换方式也有区别,常见场景如下:
1. 从字符串/字符数组解析JSON
如果原始数据是JSON格式的字符串或字符数组,直接通过构造函数或parse()方法即可完成转换:
#include <nlohmann/json.hpp> #include <string> #include <iostream> using json = nlohmann::json; int main() { // 原始字符数组数据 const char* raw_cstr = "{ \"happy\": true, \"pi\": 3.141 }"; json j1 = raw_cstr; // 原始字符串数据 std::string raw_str = "{ \"name\": \"Alice\", \"age\": 25 }"; json j2 = json::parse(raw_str); // 验证转换结果 std::cout << j1["pi"] << std::endl; std::cout << j2["name"] << std::endl; }
2. 自定义业务结构体转JSON
如果原始数据是自定义结构体,需要重载to_json函数,让nlohmann库识别结构体的序列化规则:
#include <nlohmann/json.hpp> #include <string> #include <iostream> using json = nlohmann::json; // 自定义原始业务数据结构体 struct User { std::string name; int age; bool is_vip; }; // 重载to_json:将User结构体转为JSON对象 void to_json(json& j, const User& user) { j = json{ {"name", user.name}, {"age", user.age}, {"is_vip", user.is_vip} }; } // 可选:重载from_json,实现JSON转结构体(反向操作) void from_json(const json& j, User& user) { j.at("name").get_to(user.name); j.at("age").get_to(user.age); j.at("is_vip").get_to(user.is_vip); } int main() { // 原始结构体数据 User alice = {"Alice", 25, true}; // 转换为JSON对象 json j = alice; // 输出格式化后的JSON字符串 std::cout << j.dump(4) << std::endl; }
二、TCP套接字的JSON读写操作
TCP读写的核心逻辑是:发送时将JSON序列化为字符串,接收时将字符串解析为JSON,以下是基于POSIX套接字的示例(Windows平台需调整套接字API):
1. TCP客户端发送JSON数据
#include <nlohmann/json.hpp> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string> #include <iostream> using json = nlohmann::json; int main() { // 创建TCP套接字 int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket creation failed"); return -1; } // 配置服务器地址 struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(8080); if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { perror("invalid server address"); close(sock); return -1; } // 连接服务器 if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { perror("connection failed"); close(sock); return -1; } // 构造JSON数据 json send_data = { {"type", "login"}, {"user", "Bob"}, {"timestamp", 1699999999} }; // 序列化为字符串 std::string send_str = send_data.dump(); // 发送数据(生产环境需处理粘包/分包) ssize_t sent_bytes = send(sock, send_str.c_str(), send_str.size(), 0); if (sent_bytes < 0) { perror("send failed"); } else { std::cout << "Sent " << sent_bytes << " bytes: " << send_str << std::endl; } close(sock); return 0; }
2. TCP服务器接收并解析JSON数据
#include <nlohmann/json.hpp> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string> #include <iostream> #include <cstring> using json = nlohmann::json; int main() { // 创建服务器套接字 int server_sock = socket(AF_INET, SOCK_STREAM, 0); if (server_sock < 0) { perror("socket creation failed"); return -1; } // 设置地址重用 int opt = 1; if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt failed"); close(server_sock); return -1; } // 配置服务器地址 struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(8080); // 绑定地址 if (bind(server_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind failed"); close(server_sock); return -1; } // 监听连接 if (listen(server_sock, 3) < 0) { perror("listen failed"); close(server_sock); return -1; } std::cout << "Server listening on port 8080..." << std::endl; // 接受客户端连接 struct sockaddr_in cli_addr; socklen_t cli_len = sizeof(cli_addr); int client_sock = accept(server_sock, (struct sockaddr*)&cli_addr, &cli_len); if (client_sock < 0) { perror("accept failed"); close(server_sock); return -1; } // 接收数据(缓冲区大小按需调整) char buffer[1024] = {0}; ssize_t recv_bytes = recv(client_sock, buffer, sizeof(buffer)-1, 0); if (recv_bytes < 0) { perror("recv failed"); } else { std::cout << "Received " << recv_bytes << " bytes: " << buffer << std::endl; // 解析为JSON对象,捕获解析异常 try { json recv_data = json::parse(buffer); std::cout << "Parsed JSON: " << std::endl; std::cout << recv_data.dump(4) << std::endl; // 访问JSON字段 std::cout << "User: " << recv_data["user"] << std::endl; } catch (const json::parse_error& e) { std::cerr << "JSON parse error: " << e.what() << std::endl; } } close(client_sock); close(server_sock); return 0; }
关键注意事项
- 粘包/分包处理:实际TCP通信中,JSON数据可能被拆分或合并,需自定义协议(比如在JSON前添加数据长度前缀)保证完整解析。
- 错误处理:示例仅做基础错误捕获,生产环境需完善套接字操作、JSON解析等场景的异常处理。
内容的提问来源于stack exchange,提问作者Zvi Vered
相关产品推荐
相关产品推荐

