Case1
ROS2如下代码,经常出现客户端发送异步请求没有收到回调的情况:
std::unordered_map<std::string, NodeInf> TaskManager::getAllNodes() {
if (!get_cur_host_nodes_status_cli_->wait_for_service(std::chrono::duration<double>(1))) {
MOGO_WARN("cannot call service to get cur host nodes because of [/ssm/query_agent_state] is not available");
return {};
}
get_cur_host_nodes_status_cli_->prune_pending_requests(); // 加上这一行解决问题
auto request = std::make_shared<autopilot_msgs::srv::BinarySrv::Request>();
auto response = std::make_shared<autopilot_msgs::srv::BinarySrv::Response>();
std::vector<uint8_t> bytes(hostname_.begin(), hostname_.end());
request->req = bytes;
bool hasCallBack = false;
using ServiceResponseFuture = mogo::Client<autopilot_msgs::srv::BinarySrv>::SharedFuture;
auto response_received_callback = [this, &hasCallBack](ServiceResponseFuture future) {
system_master::AgentInf agent_info;
auto response = future.get();
common::DeserializeProto(agent_info, response->resp);
if (response->resp.size() == 1 && response->resp[0] == '0') {
MOGO_WARN("the request host of req does not exist in the domain host maintained by ssm, the resp returned by ssm is [0]");
return;
}
if (agent_info.agent_state() == system_master::AgentState::DISCONNECT) {
MOGO_WARN("the node status of the agent may be changing and is unreliable");
return;
}
auto nodes = agent_info.node();
for (int i = 0; i < nodes.size(); i++) {
auto node = nodes.Get(i);
NodeInf node_inf;
node_inf.node_name_ = node.node_name();
node_inf.node_state_ = static_cast<NodeState>(node.state());
nodes_mp_[node_inf.node_name_] = node_inf;
}
hasCallBack = true;
};
auto future_result = get_cur_host_nodes_status_cli_->async_send_request(request, response_received_callback);
// mogo::spin_until_future_complete(node_handle_.get_node(), future_result) == mogo::FutureReturnCode::SUCCESS) {
// MOGO_INFO("Received response: %s", response->data.c_str());
// } else {
// MOGO_ERROR("Failed to get response within the timeout.");
// }
int count = 0;
while (!hasCallBack) {
usleep(10000);
count++;
if (!hasCallBack && count >= 100) {
MOGO_ERROR("asynchronous callback timeout, the threshold of timeout is 1s, the time slice is 10ms");
break;
}
}
return nodes_mp_;
}
在 ROS 2 中,prune_pending_requests()
是一个用于清理挂起请求的函数。它是 rclcpp::Client
类的成员函数,用于清理尚未完成的请求,以避免请求队列中的挂起请求堆积。
在 ROS 2 中,客户端(Client)与服务端(Server)之间进行通信时,客户端可能会向服务端发送请求并等待响应。如果客户端发送的请求在一定时间内没有得到响应,这些请求就会被视为挂起请求。这可能发生在网络延迟、服务端故障或其他原因导致请求无法完成的情况下。
prune_pending_requests()
函数的作用是清理这些挂起请求,以确保请求队列不会无限增长。当调用这个函数时,它会检查每个挂起请求的状态,并将超时的请求从队列中移除。
以下是一个示例代码,演示了如何使用 prune_pending_requests()
函数:
#include <rclcpp/rclcpp.hpp>
int main(int argc, char** argv) {
rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("client_node");
// 创建客户端
auto client = node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");
// 发送请求(未得到响应)
auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>();
request->a = 10;
request->b = 20;
auto future_result = client->async_send_request(request);
// 在发送请求后,等待一段时间
std::this_thread::sleep_for(std::chrono::seconds(5));
// 清理挂起的请求
client->prune_pending_requests();
// 检查请求是否已完成
if (future_result.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
auto response = future_result.get();
RCLCPP_INFO(node->get_logger(), "Result: %ld", response->sum);
} else {
RCLCPP_WARN(node->get_logger(), "Request timed out.");
}
rclcpp::shutdown();
return 0;
}
在上面的示例中,我们创建了一个客户端,向服务端发送请求,并在请求发送后等待一段时间。然后,我们调用 prune_pending_requests()
函数来清理挂起请求。最后,我们检查请求是否已完成,并根据结果进行相应的处理。
请注意,prune_pending_requests()
函数需要运行在客户端的上下文中,因此需要在适当的地方调用该函数,例如在等待请求完成之前或之后。
这个函数对于管理挂起请求队列很有用,可以防止队列无限增长,并确保及时处理请求超时的情况。