CreoOtkPluging/HttpServer.cpp
root e8491eb419 修复HttpServer字符编码问题并增强超时处理
主要修改:
- 修复HttpServer.cpp中的乱码注释导致的编译错误
- 转换文件为CRLF行尾符,添加UTF-8 BOM确保Visual Studio兼容性
- 增强Socket超时处理:添加接收/发送超时30秒配置
- 更新Config.h添加SOCKET_RECV_TIMEOUT_MS和SOCKET_SEND_TIMEOUT_MS常量
- 完善异常处理机制,确保服务线程稳定性

技术细节:
- 解决乱码注释:OPTIONS预检请求处理、查找路由处理器等10处注释
- 网络稳定性:防止recv/send操作无限阻塞导致服务不响应
- 文件编码标准化:符合项目其他文件的编码规范

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-08 14:56:44 +08:00

228 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pch.h"
#include "HttpServer.h"
#include <sstream>
#include <functional>
#pragma comment(lib, "ws2_32.lib")
HttpServer::HttpServer() : server_socket_(INVALID_SOCKET), running_(false), thread_handle_(nullptr) {
}
HttpServer::~HttpServer() {
Stop();
}
bool HttpServer::Start() {
if (running_) return true;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
return false;
}
server_socket_ = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket_ == INVALID_SOCKET) {
WSACleanup();
return false;
}
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(Config::HTTP_PORT);
if (bind(server_socket_, (struct sockaddr*)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
closesocket(server_socket_);
WSACleanup();
return false;
}
if (listen(server_socket_, SOMAXCONN) == SOCKET_ERROR) {
closesocket(server_socket_);
WSACleanup();
return false;
}
// 设置socket超时参数防止recv/send阻塞
DWORD recv_timeout = Config::SOCKET_RECV_TIMEOUT_MS;
DWORD send_timeout = Config::SOCKET_SEND_TIMEOUT_MS;
if (setsockopt(server_socket_, SOL_SOCKET, SO_RCVTIMEO, (char*)&recv_timeout, sizeof(recv_timeout)) == SOCKET_ERROR ||
setsockopt(server_socket_, SOL_SOCKET, SO_SNDTIMEO, (char*)&send_timeout, sizeof(send_timeout)) == SOCKET_ERROR) {
closesocket(server_socket_);
WSACleanup();
return false;
}
running_ = true;
thread_handle_ = CreateThread(NULL, 0, ServerThread, this, 0, NULL);
return thread_handle_ != nullptr;
}
void HttpServer::Stop() {
running_ = false;
if (server_socket_ != INVALID_SOCKET) {
closesocket(server_socket_);
server_socket_ = INVALID_SOCKET;
}
if (thread_handle_) {
WaitForSingleObject(thread_handle_, 5000);
CloseHandle(thread_handle_);
thread_handle_ = nullptr;
}
WSACleanup();
}
void HttpServer::SetRouteHandler(const std::string& path,
std::function<HttpResponse(const HttpRequest&)> handler) {
route_handlers_[path] = handler;
}
DWORD WINAPI HttpServer::ServerThread(LPVOID lpParam) {
HttpServer* server = static_cast<HttpServer*>(lpParam);
while (server->running_) {
SOCKET client_socket = accept(server->server_socket_, NULL, NULL);
if (client_socket == INVALID_SOCKET) {
if (server->running_) {
continue;
}
break;
}
// 添加异常保护,确保任何异常都不会导致服务线程崩溃
try {
server->HandleClient(client_socket);
}
catch (...) {
// 捕获所有异常确保socket正确关闭
// 异常不影响服务器继续运行
}
closesocket(client_socket);
}
return 0;
}
void HttpServer::HandleClient(SOCKET client_socket) {
char buffer[Config::BUFFER_SIZE];
int bytes_received = recv(client_socket, buffer, sizeof(buffer) - 1, 0);
// 检查recv错误和超时情况
if (bytes_received == SOCKET_ERROR) {
int error = WSAGetLastError();
if (error == WSAETIMEDOUT) {
// 接收超时,直接返回避免阻塞
return;
}
// 其他网络错误,直接返回
return;
}
if (bytes_received <= 0) {
// 连接关闭或无数据,直接返回
return;
}
buffer[bytes_received] = '\0';
std::string raw_request(buffer);
HttpRequest request = ParseRequest(raw_request);
HttpResponse response;
// OPTIONS预检请求处理CORS支持
if (request.method == "OPTIONS") {
response.status_code = 200;
response.body = "";
SendResponse(client_socket, response);
return;
}
// 查找路由处理器
auto handler_it = route_handlers_.find(request.path);
if (handler_it != route_handlers_.end()) {
response = handler_it->second(request);
} else {
response.status_code = 404;
response.body = "{\"error\":\"Not Found\"}";
}
SendResponse(client_socket, response);
}
HttpRequest HttpServer::ParseRequest(const std::string& raw_request) {
HttpRequest request;
std::istringstream stream(raw_request);
std::string line;
// 解析请求行
if (std::getline(stream, line)) {
std::istringstream request_line(line);
std::string path_with_query;
request_line >> request.method >> path_with_query;
// 处理查询参数
size_t query_pos = path_with_query.find('?');
if (query_pos != std::string::npos) {
request.path = path_with_query.substr(0, query_pos);
request.query = path_with_query.substr(query_pos + 1);
} else {
request.path = path_with_query;
}
}
// 解析请求头
while (std::getline(stream, line) && line != "\r") {
size_t colon_pos = line.find(':');
if (colon_pos != std::string::npos) {
std::string key = line.substr(0, colon_pos);
std::string value = line.substr(colon_pos + 2);
if (!value.empty() && value.back() == '\r') {
value.pop_back();
}
request.headers[key] = value;
}
}
// 解析请求体
std::string body_line;
while (std::getline(stream, body_line)) {
request.body += body_line + "\n";
}
if (!request.body.empty()) {
request.body.pop_back(); // 移除最后的换行符
}
return request;
}
void HttpServer::SendResponse(SOCKET client_socket, const HttpResponse& response) {
std::ostringstream response_stream;
// 状态行
response_stream << "HTTP/1.1 " << response.status_code << " ";
switch (response.status_code) {
case 200: response_stream << "OK"; break;
case 404: response_stream << "Not Found"; break;
case 500: response_stream << "Internal Server Error"; break;
default: response_stream << "Unknown"; break;
}
response_stream << "\r\n";
// 响应头
for (const auto& header : response.headers) {
response_stream << header.first << ": " << header.second << "\r\n";
}
response_stream << "Content-Length: " << response.body.length() << "\r\n";
response_stream << "Connection: close\r\n\r\n";
// 响应体
response_stream << response.body;
std::string response_str = response_stream.str();
send(client_socket, response_str.c_str(), (int)response_str.length(), 0);
}