0. Problems
很多时候实现某种功能,需要在不同进程间发送数据,目前有几种主流的方法,如
让python和C/C++程序互相发送数据,其实有几种方法:
- 共享内存
- 共享文件
- Socket通信
在这里只提供Socket通信的例程,共享文件很容易实现,就是可靠性差点,共享内存也是一种常用的方法。
其实,如果使用的是ROS框架,更加方便,提供了三种通信方法 (Topic/Server/Action),具体内容可以看我之前的ROS Learning篇的内容,请点这里。
1. Solutions
先上例程
1)Python端发送:
import socket
import json# 创建Socket对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 连接C++程序
cpp_host = '127.0.0.1' # C++程序所在的主机
cpp_port = 8888 # C++程序监听的端口
sock.connect((cpp_host, cpp_port))# 读取json文件并发送给C++程序
with open('response.json', 'r') as file:json_data = file.read()sock.sendall(json_data.encode())# 接收C++程序的响应
response = sock.recv(1024).decode()
if len(response) > 0:print("Received response from C++ program:", response)
else:print("Failed to receive response from C++ program.")# 关闭Socket连接
sock.close()
2)C++端接收:
/** @Descripttion: Robot2.5* @version: 20220211* @Author: Will Yip* @Date: 2024-02-21 15:43:37* @LastEditors: Will Yip* @LastEditTime: 2024-02-21 16:25:42*/
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>int main() {// 创建Socketint sockfd = socket(AF_INET, SOCK_STREAM, 0);// 绑定Socket到指定端口sockaddr_in addr{};addr.sin_family = AF_INET;addr.sin_port = htons(8888); // 监听的端口addr.sin_addr.s_addr = INADDR_ANY;bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));// 监听连接listen(sockfd, 1);// 接受连接sockaddr_in clientAddr{};socklen_t clientAddrLen = sizeof(clientAddr);int clientSock = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);// 接收来自Python程序的数据char buffer[1024];memset(buffer, 0, sizeof(buffer));int bytesRead = recv(clientSock, buffer, sizeof(buffer), 0);// 判断是否接收到了数据if (bytesRead > 0) {// 处理收到的数据(这里假设数据是JSON格式)std::cout << "Received JSON data from Python program: " << buffer << std::endl;// 发送响应给Python程序const char* response = "Data received successfully!";send(clientSock, response, strlen(response), 0);} else {std::cout << "Failed to receive data from Python program." << std::endl;}// 关闭连接// close(clientSock); // dont close this connection, it will causes a problem when relaunch this receiver next time, it cant create 8888 port.close(sockfd);return 0;
}
然后就可以开始测试了,记住要先启动C++接收端,再启动python发送端,不然就报错,提示connection error
。
在调试时也会用上一些指令,可以帮助我们做一些检查
在Ubuntu中有两个常用的指令用来查看端口情况:
- netstat
- lsof
这两个指令都能显示当前的端口信息。
- netstat
常用netstat -tuln
,加上后面的参数可以帮助显示TCP和UDP协议的端口-t
表示显示TCP协议的端口;-u
表示显示UDP协议的端口;-l
表示仅显示监听状态的端口;-n
表示以数字形式显示地址和端口号,而不是尝试解析主机名、服务名等。
显示如下:
- lsof
lsof
的用法是lsof -i:port_num
,里面的port_num
就是端口号,可以是根据netstat查询到的端口号。
PS:端口号前加不加空格都行,
以下是示例: