本地TCP通讯(C++)

概要

利用TCP技术,实现本地ROS1和ROS2的通讯。

服务端代码

头文件

cpp 复制代码
#include <ros/ros.h>
#include "std_msgs/String.h"
#include "std_msgs/Bool.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include "geometry_msgs/Twist.h"

using namespace std;


class TCPPublisher
{
    public:
        TCPPublisher();
        ~TCPPublisher();
        void cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg);

    private:
        ros::NodeHandle n, nPrivate;
        ros::Publisher tcpPub;
        ros::Subscriber cmdVelSub;
        // 创建服务器套接字
        int serverSocket;
        // 设置服务器地址结构
        sockaddr_in serverAddr;
        int clientSocket;
        std::string topicStatus;
};

源代码

cpp 复制代码
#include "./tcp_pub/tcp_pub.h"


TCPPublisher::TCPPublisher():nPrivate("~")
{
    nPrivate.param("topicStatus", topicStatus, std::string("/cmd_vel"));
    /*订阅话题*/
    cmdVelSub = n.subscribe(topicStatus.c_str(), 10, &TCPPublisher::cmdVelCallback, this);

    serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    // 设置服务器地址结构
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(8080); // 服务器监听的端口号

    // 绑定套接字
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        std::cerr << "Bind failed." << std::endl;
        close(serverSocket);
        return;
    }

    // 监听连接
    if (listen(serverSocket, SOMAXCONN) == -1) {
        std::cerr << "Listen failed." << std::endl;
        close(serverSocket);
        return;
    }

    std::cout << "Server is listening for incoming connections..." << std::endl;

    ROS_INFO("TCPPublisher init successfully!!!");
}

TCPPublisher::~TCPPublisher()
{
    close(serverSocket);
}


void TCPPublisher::cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg)
{
    float velX = msg->linear.x;
    float angularZ = msg->angular.z;
    // ROS_INFO("velX : %f, angularZ : %f", velX, angularZ);

    // 定义字符数组,用于存储转换后的结果
    char buffer[50]; // 适当调整数组大小以适应你的需求
    snprintf(buffer, sizeof(buffer), "%f,%f", velX, angularZ);
    // ROS_INFO("buffer %s", buffer);

    // 接受连接
    int clientSocket = accept(serverSocket, NULL, NULL);
    if (clientSocket == -1) {
        std::cerr << "Accept failed." << std::endl;
        close(serverSocket);
        return;
    }

    std::cout << "Connection established with a client." << std::endl;

    // 发送消息给客户端
    const char* message = buffer;
    ROS_INFO("message %s", message);

    if (send(clientSocket, message, strlen(message), 0) == -1) {
        std::cerr << "Error sending message." << std::endl;
    }

    // 关闭客户端套接字
    close(clientSocket);
}

int main(int argc, char **argv) {
  //创建节点
  ros::init(argc, argv, "pure_pursuit");
  TCPPublisher tp;  
  ros::spin();
  return 0;
}

客户端代码

cpp 复制代码
#include <rclcpp/rclcpp.hpp>
#include <geometry_msgs/msg/twist.hpp>
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(int argc, char * argv[]) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<rclcpp::Node>("tcp_client");
    /*define publisher*/
    rclcpp::Publisher<geometry_msgs::msg::Twist>::SharedPtr cmd_pub_;
   // Advertise velocity commands
    auto default_qos = rclcpp::QoS(rclcpp::SystemDefaultsQoS());
    cmd_pub_ = node->create_publisher<geometry_msgs::msg::Twist>("cmd_vel", default_qos);


    //连接到服务器
    // if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
    //     std::cerr << "Connection failed." << std::endl;
    //     close(clientSocket);
    //     return 1;
    // }

    // std::cout << "Connected to the server." << std::endl;

    while (true) {

        // 创建客户端套接字
        int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
        if (clientSocket == -1) {
            std::cerr << "Failed to create client socket." << std::endl;
            return 1;
        }

        // 设置服务器地址结构
        sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // 本地回环地址 // 服务器的 IP 地址
        serverAddr.sin_port = htons(8080); // 服务器监听的端口号

        // 连接到服务器
        if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
            std::cerr << "Connection failed." << std::endl;
            close(clientSocket);
            // return 1;
        }

        // std::cout << "Connected to the server." << std::endl;
        // 接收消息
        char buffer[50];
        memset(buffer, 0, sizeof(buffer));
        if (recv(clientSocket, buffer, sizeof(buffer), 0) == -1) {
            std::cerr << "Error receiving message." << std::endl;
        } else {
            std::cout << "Received message from server: " << buffer << std::endl;

            // 定义两个变量来存储解析后的浮点数
            float floatValue1, floatValue2;

            // 使用 sscanf 解析字符数组
            if (std::sscanf(buffer, "%f,%f", &floatValue1, &floatValue2) == 2) {
                // 打印解析结果
                std::cout << "解析后的浮点数1: " << floatValue1 << std::endl;
                std::cout << "解析后的浮点数2: " << floatValue2 << std::endl;
            } else {
                // 解析失败
                std::cerr << "解析失败" << std::endl;
            }
         
            geometry_msgs::msg::Twist cmd_msg;
            cmd_msg.linear.x = floatValue1;
            cmd_msg.angular.z = floatValue2;
            cmd_pub_->publish(cmd_msg);
            std::cout << "Publishing zero speed to /cmd_vel. " << std::endl;
        }

        // 关闭客户端套接字
        close(clientSocket);
        // 在这里可以添加一些延时,以避免过于频繁地连接服务器
        sleep(0.1);
    }



    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}
相关推荐
clear sky .2 分钟前
[TCP]MCU上如何编辑TCP服务端程序,思路框架
服务器·网络·tcp/ip
程序喵大人13 分钟前
【C++进阶】STL算法与函数对象 -【C++进阶】STL算法与函数对象
开发语言·c++·算法
奈斯先生Vector22 分钟前
2026 AIGC API 网关韧性评测:为什么 HTTP 200 不等于有效交付
网络协议·http·aigc
我不会插花弄玉23 分钟前
10.list【由浅入深-C++】
数据结构·c++·list
旖旎夜光1 小时前
C++(类与对象)(下)
开发语言·c++·学习
江屿风1 小时前
【科普】【差集&交集概念落地云相册】流食般投喂
开发语言·c++·笔记·算法·云相册
拾光Ծ1 小时前
【Linux网络】深入理解网络层:从IP协议格式,子网划分到NAT与路由机制
linux·网络·网络协议·tcp/ip·计算机网络
2401_8685347810 小时前
RTOS之RT-Thread & Linux:线程/进程管理与调度核心差异分析
c++·python
郝学胜-神的一滴11 小时前
Qt 高级编程 040:按钮悬浮弹出滑块弹窗的完整攻略
开发语言·c++·qt·软件工程·用户界面
全麦面包 time展天14 小时前
瀚海拾贝(一)HTTP协议/IIS 原理及ASP.NET运行机制浅析【图解】
网络协议·http·asp.net