WebServer.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #define WIN32_LEAN_AND_MEAN
  2. #include <windows.h>
  3. #include <winsock2.h>
  4. #include <ws2tcpip.h>
  5. #include <shlwapi.h>
  6. #include "WebServer.h"
  7. #include "WebSocketSession.h"
  8. #include "Logger.h"
  9. #include <fstream>
  10. #include <sstream>
  11. #include <iostream>
  12. WebServer::WebServer(int port, bool use_dll) : port_(port), acceptor_(ioc_), running_(false)
  13. {
  14. websocket_handler_ = std::make_shared<WebSocketHandler>(use_dll);
  15. }
  16. WebServer::~WebServer()
  17. {
  18. Stop();
  19. }
  20. bool WebServer::Start()
  21. {
  22. try
  23. {
  24. // 初始化WebSocketHandler(包括ActiveX控件)
  25. if (!websocket_handler_->Initialize())
  26. {
  27. LOG_ERROR("Failed to initialize WebSocketHandler");
  28. return false;
  29. }
  30. // 设置端点
  31. tcp::endpoint endpoint(net::ip::make_address("0.0.0.0"), port_);
  32. // 打开acceptor
  33. acceptor_.open(endpoint.protocol());
  34. acceptor_.set_option(net::socket_base::reuse_address(true));
  35. acceptor_.bind(endpoint);
  36. acceptor_.listen(net::socket_base::max_listen_connections);
  37. running_ = true;
  38. // 开始接受连接
  39. DoAccept();
  40. // 在单独线程中运行io_context
  41. server_thread_ = std::thread([this]()
  42. { ioc_.run(); });
  43. LOG_INFO("WebServer started on port " + std::to_string(port_));
  44. return true;
  45. }
  46. catch (const std::exception &e)
  47. {
  48. LOG_ERROR("Failed to start WebServer: " + std::string(e.what()));
  49. return false;
  50. }
  51. }
  52. void WebServer::Stop()
  53. {
  54. if (running_)
  55. {
  56. running_ = false;
  57. // 停止acceptor
  58. beast::error_code ec;
  59. acceptor_.close(ec);
  60. // 停止io_context
  61. ioc_.stop();
  62. // 等待线程结束
  63. if (server_thread_.joinable())
  64. {
  65. server_thread_.join();
  66. }
  67. // 清理WebSocketHandler
  68. if (websocket_handler_)
  69. {
  70. websocket_handler_->Cleanup();
  71. }
  72. LOG_INFO("WebServer stopped");
  73. }
  74. }
  75. void WebServer::DoAccept()
  76. {
  77. acceptor_.async_accept(
  78. net::make_strand(ioc_),
  79. [self = shared_from_this()](beast::error_code ec, tcp::socket socket)
  80. {
  81. self->OnAccept(ec, std::move(socket));
  82. });
  83. }
  84. void WebServer::OnAccept(beast::error_code ec, tcp::socket socket)
  85. {
  86. if (ec)
  87. {
  88. if (ec != net::error::operation_aborted)
  89. {
  90. LOG_ERROR("Accept error: " + ec.message());
  91. }
  92. return;
  93. }
  94. // 创建HTTP会话来处理连接
  95. std::make_shared<HttpSession>(std::move(socket), shared_from_this())->run();
  96. // 继续接受新连接
  97. if (running_)
  98. {
  99. DoAccept();
  100. }
  101. }
  102. std::string WebServer::GetStaticFileContent(const std::string &path)
  103. {
  104. // 获取可执行文件所在目录
  105. char buffer[MAX_PATH];
  106. GetModuleFileNameA(NULL, buffer, MAX_PATH);
  107. std::string::size_type pos = std::string(buffer).find_last_of("\\");
  108. std::string exe_path = std::string(buffer).substr(0, pos);
  109. std::string file_path;
  110. if (path == "/" || path == "/index.html")
  111. {
  112. file_path = exe_path + "\\web\\index.html";
  113. }
  114. else if (path == "/style.css")
  115. {
  116. file_path = exe_path + "\\web\\style.css";
  117. }
  118. else if (path == "/script.js")
  119. {
  120. file_path = exe_path + "\\web\\script.js";
  121. }
  122. else
  123. {
  124. return "";
  125. }
  126. // 以二进制模式打开文件,避免编码问题
  127. std::ifstream file(file_path, std::ios::binary);
  128. if (!file.is_open())
  129. {
  130. LOG_ERROR("Failed to open file: " + file_path);
  131. return "";
  132. }
  133. // 读取文件内容
  134. std::stringstream content_buffer;
  135. content_buffer << file.rdbuf();
  136. return content_buffer.str();
  137. }
  138. std::string WebServer::GetMimeType(const std::string &path)
  139. {
  140. if (path == "/" || path == "/index.html" || path.ends_with(".html"))
  141. {
  142. return "text/html; charset=utf-8";
  143. }
  144. if (path.ends_with(".css"))
  145. {
  146. return "text/css; charset=utf-8";
  147. }
  148. if (path.ends_with(".js"))
  149. {
  150. return "application/javascript; charset=utf-8";
  151. }
  152. if (path.ends_with(".json"))
  153. {
  154. return "application/json; charset=utf-8";
  155. }
  156. return "text/plain; charset=utf-8";
  157. }
  158. void WebServer::HandleHttpRequest(http::request<http::dynamic_body> &&req,
  159. std::function<void(http::response<http::dynamic_body>)> send)
  160. {
  161. // 处理普通HTTP请求
  162. auto const bad_request = [&req](beast::string_view why)
  163. {
  164. http::response<http::dynamic_body> res{http::status::bad_request, req.version()};
  165. res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
  166. res.set(http::field::content_type, "text/html; charset=utf-8");
  167. res.keep_alive(req.keep_alive());
  168. beast::ostream(res.body()) << "Bad request: " << why;
  169. res.prepare_payload();
  170. return res;
  171. };
  172. auto const not_found = [&req](beast::string_view target)
  173. {
  174. http::response<http::dynamic_body> res{http::status::not_found, req.version()};
  175. res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
  176. res.set(http::field::content_type, "text/html; charset=utf-8");
  177. res.keep_alive(req.keep_alive());
  178. beast::ostream(res.body()) << "The resource '" << target << "' was not found.";
  179. res.prepare_payload();
  180. return res;
  181. };
  182. // 确保我们可以处理这个方法
  183. if (req.method() != http::verb::get && req.method() != http::verb::head)
  184. {
  185. return send(bad_request("Unknown HTTP-method"));
  186. }
  187. // 请求路径不能包含".."
  188. if (req.target().empty() || req.target()[0] != '/' || req.target().find("..") != beast::string_view::npos)
  189. {
  190. return send(bad_request("Illegal request-target"));
  191. }
  192. // 获取文件内容
  193. std::string path = std::string(req.target());
  194. std::string content = GetStaticFileContent(path);
  195. if (content.empty())
  196. {
  197. return send(not_found(req.target()));
  198. }
  199. // 创建响应
  200. http::response<http::dynamic_body> res{http::status::ok, req.version()};
  201. res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
  202. res.set(http::field::content_type, GetMimeType(path));
  203. res.keep_alive(req.keep_alive());
  204. // 设置响应体
  205. beast::ostream(res.body()) << content;
  206. res.prepare_payload();
  207. return send(std::move(res));
  208. }
  209. // HttpSession实现
  210. HttpSession::HttpSession(tcp::socket &&socket, std::shared_ptr<WebServer> server)
  211. : stream_(std::move(socket)), server_(server)
  212. {
  213. }
  214. void HttpSession::run()
  215. {
  216. net::dispatch(stream_.get_executor(),
  217. beast::bind_front_handler(&HttpSession::do_read, shared_from_this()));
  218. }
  219. void HttpSession::do_read()
  220. {
  221. req_ = {};
  222. stream_.expires_after(std::chrono::seconds(30));
  223. http::async_read(stream_, buffer_, req_,
  224. beast::bind_front_handler(&HttpSession::on_read, shared_from_this()));
  225. }
  226. void HttpSession::on_read(beast::error_code ec, std::size_t bytes_transferred)
  227. {
  228. boost::ignore_unused(bytes_transferred);
  229. if (ec == http::error::end_of_stream)
  230. {
  231. return do_close();
  232. }
  233. if (ec)
  234. {
  235. LOG_ERROR("HTTP read error: " + ec.message());
  236. return;
  237. }
  238. // 检查是否是WebSocket升级请求
  239. if (websocket::is_upgrade(req_))
  240. {
  241. // 释放socket并传递给WebSocket会话
  242. tcp::socket socket = stream_.release_socket();
  243. // 创建WebSocket会话
  244. auto ws_session = std::make_shared<WebSocketSession>(std::move(socket), std::move(req_));
  245. // 设置WebSocketHandler引用
  246. ws_session->set_websocket_handler(server_->GetWebSocketHandler());
  247. // 设置消息处理回调
  248. ws_session->set_message_handler([server = server_](std::shared_ptr<WebSocketSession> session, const std::string &message)
  249. { server->GetWebSocketHandler()->HandleMessage(session, message); });
  250. // 添加到WebSocket处理器
  251. server_->GetWebSocketHandler()->AddClient(ws_session);
  252. ws_session->run();
  253. return;
  254. }
  255. // 处理普通HTTP请求
  256. server_->HandleHttpRequest(std::move(req_),
  257. [self = shared_from_this()](http::response<http::dynamic_body> res)
  258. {
  259. // 发送响应
  260. auto sp = std::make_shared<http::response<http::dynamic_body>>(std::move(res));
  261. http::async_write(self->stream_, *sp,
  262. [self, sp](beast::error_code ec, std::size_t bytes_transferred)
  263. {
  264. self->on_write(sp->need_eof(), ec, bytes_transferred);
  265. });
  266. });
  267. }
  268. void HttpSession::on_write(bool close, beast::error_code ec, std::size_t bytes_transferred)
  269. {
  270. boost::ignore_unused(bytes_transferred);
  271. if (ec)
  272. {
  273. LOG_ERROR("HTTP write error: " + ec.message());
  274. return;
  275. }
  276. if (close)
  277. {
  278. return do_close();
  279. }
  280. // 读取另一个请求
  281. do_read();
  282. }
  283. void HttpSession::do_close()
  284. {
  285. beast::error_code ec;
  286. stream_.socket().shutdown(tcp::socket::shutdown_send, ec);
  287. }