Unity客户端交互时C++ Boost Ptree多人服务器出现段错误
问题描述
正在构建Node.js与C双服务器架构的多人应用,Unity客户端连接并发送用户数据后,C服务器触发段错误直接退出,无任何提示。该问题仅在Unity客户端触发,Postman测试无异常。已确认客户端发送数据正常、传输过程无问题,但C++服务器有时无法正确获取JSON请求体。
核心问题排查与修复方案
1. 异常处理逻辑错误(直接触发崩溃)
RouteRequest函数的catch块存在严重错误:
catch (const std::exception& e) { throw e.what(); // 错误:抛出const char*类型,无法被std::exception捕获,直接触发未捕获异常崩溃 std::cout << e.what() << std::endl; sendHttpResponse(response, 500, "text/html", e.what()); }
修复方案:
去掉错误的抛出语句,保留正常错误处理流程;若需重新抛出异常,使用throw;保留原异常类型:
catch (const std::exception& e) { std::cout << e.what() << std::endl; sendHttpResponse(response, 500, "text/html", e.what()); // 如需向上传递异常,使用以下语句而非throw e.what(); // throw; }
2. 未读取HTTP请求体(JSON数据丢失)
当前BufferToString仅读取HTTP头部(到\r\n\r\n为止),完全未处理Unity发送的JSON请求体,导致后续解析Player对象时因无效数据触发异常崩溃。
修复方案:
从HTTP头部提取Content-Length字段,根据长度读取完整请求体:
std::string BufferToString(tcp::socket& socket, std::string& route, std::string& Method) { boost::asio::streambuf request_buffer; boost::system::error_code error; try { // 读取HTTP头部 boost::asio::read_until(socket, request_buffer, "\r\n\r\n", error); if (error) { throw std::runtime_error(error.message()); } std::string header_data(boost::asio::buffers_begin(request_buffer.data()), boost::asio::buffers_end(request_buffer.data())); // 解析Content-Length size_t content_length = 0; size_t cl_pos = header_data.find("Content-Length: "); if (cl_pos != std::string::npos) { size_t cl_end = header_data.find("\r\n", cl_pos); std::string cl_str = header_data.substr(cl_pos + 16, cl_end - (cl_pos + 16)); content_length = std::stoull(cl_str); } // 读取JSON请求体 std::string body_data; if (content_length > 0) { body_data.resize(content_length); boost::asio::read(socket, boost::asio::buffer(body_data), error); if (error) { throw std::runtime_error(error.message()); } } // 解析请求方法与路由 size_t path_start = header_data.find(" "); if (path_start != std::string::npos) { size_t path_end = header_data.find(" ", path_start + 1); route = header_data.substr(path_start + 1, path_end - path_start - 1); } else { std::cout << "String error: \n" << header_data << std::endl; } Method = header_data.substr(0, header_data.find(" ")); // 返回JSON请求体,供后续解析 return body_data; } catch (const std::exception& ex) { std::cout << "Exception occurred: " << ex.what() << std::endl; return " "; } }
3. 同步连接处理导致资源堆积
主函数中同步处理连接,Unity在FixedUpdate(默认0.02秒/次)高频发送请求时,会导致大量连接阻塞、资源未正确释放,触发内存错误。
修复方案:
用线程池或后台线程异步处理连接,避免阻塞主线程:
#include <thread> #include <memory> int main() { boost::asio::io_context io_context; std::string raw_ip_address = "0.0.0.0"; boost::system::error_code ec; boost::asio::ip::address ip_address = boost::asio::ip::address::from_string(raw_ip_address, ec); if (ec.value() != 0) { std::cout << "Failed to parse the IP address. Error code = " << ec.value() << ". Message: " << ec.message(); return ec.value(); } tcp::endpoint tp(ip_address, 8081); tcp::acceptor acceptor(io_context, tp); Rooms MainRooms; std::mutex rooms_mutex; // 确保Rooms线程安全 while (true) { auto socket = std::make_shared<tcp::socket>(io_context); acceptor.accept(*socket); // 后台线程处理请求,避免阻塞主线程 std::thread([socket, &MainRooms, &rooms_mutex]() { std::lock_guard<std::mutex> lock(rooms_mutex); RouteRequest(*socket, MainRooms); }).detach(); } return 0; }
注:需确保Rooms类的addRoomMate方法线程安全,必要时添加互斥锁。
4. JSON解析容错与段错误调试
- Player构造函数容错:使用成熟JSON库(如nlohmann/json)解析数据,避免手动解析出错;确保构造函数抛出的异常均为
std::exception类型。 - 段错误定位:编译时添加
-g参数生成调试信息,用GDB调试:gdb ./your_server_executable run # 启动服务器 bt # 触发崩溃后查看调用栈,定位崩溃位置
内容的提问来源于stack exchange,提问作者PAVAN PRASAD 2022
相关产品推荐
相关产品推荐

