修改已知bug
This commit is contained in:
parent
209258589e
commit
222e816d5e
@ -45,21 +45,24 @@ void TunnelClient::start()
|
|||||||
void TunnelClient::stop()
|
void TunnelClient::stop()
|
||||||
{
|
{
|
||||||
running_.store(false);
|
running_.store(false);
|
||||||
if (client_)
|
|
||||||
|
ws_client* cli = client_; // 拷贝一份,避免 race
|
||||||
|
if (cli)
|
||||||
{
|
{
|
||||||
client_->get_io_service().post(
|
cli->get_io_service().post(
|
||||||
[this]()
|
[this, cli]()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
websocketpp::lib::error_code ec;
|
websocketpp::lib::error_code ec;
|
||||||
client_->close(hdl_, websocketpp::close::status::going_away, "stop", ec);
|
cli->close(hdl_, websocketpp::close::status::going_away, "stop", ec);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (th_.joinable()) th_.join();
|
if (th_.joinable()) th_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,83 +207,106 @@ void TunnelClient::handle_request_and_reply(const json& req)
|
|||||||
|
|
||||||
void TunnelClient::run_loop()
|
void TunnelClient::run_loop()
|
||||||
{
|
{
|
||||||
ws_client c;
|
|
||||||
c.clear_access_channels(websocketpp::log::alevel::all);
|
|
||||||
c.init_asio();
|
|
||||||
|
|
||||||
client_ = &c;
|
|
||||||
|
|
||||||
c.set_open_handler(
|
|
||||||
[this](websocketpp::connection_hdl h)
|
|
||||||
{
|
|
||||||
hdl_ = h;
|
|
||||||
std::printf("[Tunnel] Connected to server\n");
|
|
||||||
});
|
|
||||||
|
|
||||||
c.set_close_handler([this](websocketpp::connection_hdl) { std::printf("[Tunnel] Disconnected from server\n"); });
|
|
||||||
|
|
||||||
c.set_fail_handler([this](websocketpp::connection_hdl) { std::printf("[Tunnel] Connect failed\n"); });
|
|
||||||
|
|
||||||
c.set_message_handler(
|
|
||||||
[this](websocketpp::connection_hdl, ws_client::message_ptr msg)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (msg->get_opcode() != websocketpp::frame::opcode::text)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] ignore non-text msg from server\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto payload = msg->get_payload();
|
|
||||||
json req = json::parse(payload);
|
|
||||||
|
|
||||||
// 同步处理会阻塞 websocket 线程:这里开线程处理,避免卡住心跳/读写
|
|
||||||
std::thread(
|
|
||||||
[this, req]()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handle_request_and_reply(req);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] handler exception: %s\n", e.what());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] handler unknown exception\n");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] JSON parse error: %s\n", e.what());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] JSON parse unknown error\n");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
websocketpp::lib::error_code ec;
|
|
||||||
auto conn = c.get_connection(ws_url_, ec);
|
|
||||||
if (ec)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] Connection init failed: %s\n", ec.message().c_str());
|
|
||||||
client_ = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
c.connect(conn);
|
|
||||||
|
|
||||||
// 用 run():稳定事件循环
|
|
||||||
while (running_.load())
|
while (running_.load())
|
||||||
{
|
{
|
||||||
|
// 每次循环都创建一个新的 client,避免 websocketpp 状态复用崩溃
|
||||||
|
ws_client c;
|
||||||
|
c.clear_access_channels(websocketpp::log::alevel::all);
|
||||||
|
c.clear_error_channels(websocketpp::log::elevel::all);
|
||||||
|
|
||||||
|
c.init_asio();
|
||||||
|
|
||||||
|
// (可选但推荐)让 run() 不会因为没有 work 而提前退出
|
||||||
|
c.start_perpetual();
|
||||||
|
|
||||||
|
// 让 stop() 能安全拿到当前 client
|
||||||
|
{
|
||||||
|
// 如果你不想引入 mutex,这段也可以不加,但建议加
|
||||||
|
client_ = &c;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.set_open_handler(
|
||||||
|
[this](websocketpp::connection_hdl h)
|
||||||
|
{
|
||||||
|
hdl_ = h;
|
||||||
|
std::printf("[Tunnel] Connected to server\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
c.set_close_handler(
|
||||||
|
[this, &c](websocketpp::connection_hdl)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] Disconnected from server\n");
|
||||||
|
// 让 run() 退出,进入下一轮重连
|
||||||
|
c.stop_perpetual();
|
||||||
|
c.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
c.set_fail_handler(
|
||||||
|
[this, &c](websocketpp::connection_hdl)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] Connect failed\n");
|
||||||
|
// 让 run() 退出,进入下一轮重连
|
||||||
|
c.stop_perpetual();
|
||||||
|
c.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
c.set_message_handler(
|
||||||
|
[this](websocketpp::connection_hdl, ws_client::message_ptr msg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (msg->get_opcode() != websocketpp::frame::opcode::text)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] ignore non-text msg from server\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
json req = json::parse(msg->get_payload());
|
||||||
|
|
||||||
|
// 你原来的做法:起线程处理本地 HTTP,OK
|
||||||
|
std::thread(
|
||||||
|
[this, req]()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handle_request_and_reply(req);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] handler exception: %s\n", e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] handler unknown exception\n");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] JSON parse error: %s\n", e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] JSON parse unknown error\n");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
websocketpp::lib::error_code ec;
|
||||||
|
auto conn = c.get_connection(ws_url_, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
std::printf("[Tunnel] Connection init failed: %s\n", ec.message().c_str());
|
||||||
|
client_ = nullptr;
|
||||||
|
// 这里别直接 return,继续重试
|
||||||
|
goto retry_sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.connect(conn);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// 阻塞运行,直到 fail/close 里 stop(),或 stop() 主动 close
|
||||||
c.run();
|
c.run();
|
||||||
// run() 返回说明 stopped 了,稍等再重连
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
@ -291,25 +317,15 @@ void TunnelClient::run_loop()
|
|||||||
std::printf("[Tunnel] run unknown exception\n");
|
std::printf("[Tunnel] run unknown exception\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_ = nullptr;
|
||||||
|
|
||||||
if (!running_.load()) break;
|
if (!running_.load()) break;
|
||||||
|
|
||||||
|
retry_sleep:
|
||||||
std::printf("[Tunnel] reconnecting in 2s...\n");
|
std::printf("[Tunnel] reconnecting in 2s...\n");
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||||
|
|
||||||
// 重建连接
|
|
||||||
c.reset();
|
|
||||||
c.init_asio();
|
|
||||||
|
|
||||||
websocketpp::lib::error_code ec2;
|
|
||||||
auto conn2 = c.get_connection(ws_url_, ec2);
|
|
||||||
if (ec2)
|
|
||||||
{
|
|
||||||
std::printf("[Tunnel] reconnect init failed: %s\n", ec2.message().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
c.connect(conn2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::printf("[Tunnel] Loop exit\n");
|
|
||||||
client_ = nullptr;
|
client_ = nullptr;
|
||||||
|
std::printf("[Tunnel] Loop exit\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user