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() {
// 创建Socket
int 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:端口号前加不加空格都行,
以下是示例: