因近期工作需要,需要用python解析数据发送到c++程序端做处理,然后用Python可视化c++端的结果,故汇总了一些python与c++进程间通信的方式。
代码都是在Ubuntu上开发的,在windows上可能不通用。都是些简单的示例,可以在这个基础上扩展。都是些简单代码,复杂的实现就不讨论了…
同时,这些通信方式在同语言之间的进程也是可以通用的。另外,工程文件源码在文章末尾,记得点赞收藏。
最简单的做法,本地新建两个文件,相互读写,但需要顺序性,所以用到管道的阻塞特性。
可以先参考Linux管道读写阻塞,大致是管道可以理解为文件,写的时候读会阻塞,读的时候写会阻塞。
定义python程序为node1,c++程序为node2。node1往node2发送信息为管道1,node2往node1发送信息为管道2。
执行的顺序如下,node1写入管道1,node2读取管道1,node2写入管道2,node1读取管道1。因为管道的阻塞性,因此可以实现该顺序的通信。
示例如下,放了跨语言通信的demo,另外c++和python单语言进程间通信的代码也写了,见文章末尾。
import os
import time
# node1
def TestIFIO():
input_file = "/tmp/node2_to_node1.tmp"
output_file = "/tmp/node1_to_node2.tmp"
# 1.create fifo
if not os.path.exists(input_file):
os.mkfifo(input_file, 0o666)
if not os.path.exists(output_file):
os.mkfifo(output_file, 0o666)
# 2.open pipe
print('init write pipe: ' + output_file)
fout = os.open(output_file, os.O_WRONLY)
print('init read pipe: ' + input_file)
fin = os.open(input_file, os.O_RDONLY)
# 3.write and read data
send_str = "How are you?"
while True:
try:
os.write(fout, str.encode(send_str))
except:
print("node2 closed, exit!")
break
print("send: ", send_str)
recv_str = os.read(fin, 1024).decode()[:-1]
print("recv: ", recv_str)
time.sleep(0.5)
os.close(fin)
os.close(fout)
if __name__ == '__main__':
TestIFIO()
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INPUT_PATH_NAME "/tmp/node1_to_node2.tmp"
#define OUTPUT_PATH_NAME "/tmp/node2_to_node1.tmp"
// node2
int main() {
int fin = open(INPUT_PATH_NAME, O_RDONLY);
int fout = open(OUTPUT_PATH_NAME, O_WRONLY);
char buffer[1024]; // 定义接受的文件大小,可以设大点,1024*1024*n
while (true) {
memset(buffer, 0, sizeof(buffer));
if (read(fin, buffer, sizeof(buffer)) <= 0) {
printf("node1 closed, exit!\n");
break;
}
printf("receive: %s\n", buffer);
std::stringstream ss;
ss << "I'm fine, thx!";
if (write(fout, ss.str().c_str(), ss.str().length() + 1) <= 0) {
break;
}
printf("send : %s\n", ss.str().c_str());
}
close(fin);
close(fout);
return 0;
}
个人觉得还是这个好用方便,主要跟文件操作打交道的我都不喜欢
socket
用于网络服务,把复杂的TCP/IP协议封装,具体实现几次握手不用了解了(想了解可以百度了,这里不多做介绍),只需要调用接口就可以实现数据通信了.。
socket分为服务端
和客户端
,先启动服务端后,客户端向服务端发送数据,服务端接受数据并返回消息给客户端。
示例使用安全可靠的TCP协议SOCK_STREAM
socket比较方便,所以c++和python我分别都写了客户端和服务端,都比较简单,可以交叉通信,也可以同语言通信,所以总共可以四种组合通信,满足服务端和客户端的组合即可。
import socket
import time
def TestClient():
server_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_client.connect(("localhost", 8888))
info = "How are you?"
while True:
server_client.send(bytes(info, encoding='utf-8'))
print("send : ", info)
recv_str = server_client.recv(1024)
if not recv_str:
break
print("receive: ", recv_str.decode("utf-8"))
time.sleep(0.5)
server_client.close()
print("server end, exit!")
exit()
if __name__ == '__main__':
TestClient()
import socket
import time
def TestServer():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 8888))
server.listen(5)
connection, address = server.accept()
print(connection, address)
while True:
recv_str = connection.recv(1024)
recv_str = recv_str.decode("ascii")
if not recv_str:
break
print("receive:{}".format(recv_str))
send_str = "I'm fine, thx!"
connection.send(bytes(send_str, encoding="ascii"))
print("send: {}".format(send_str))
time.sleep(0.5)
connection.close()
server.close()
print("client end, exit!")
exit()
if __name__ == '__main__':
TestServer()
c++ 客户端
其中每个函数都会有返回值,示例简单就没做异常判断了,可以点开每个函数定义查看。
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main() {
// 1. 创建客户端,并连接到服务端
int sock_client = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
connect(sock_client, (sockaddr*)&server_addr, sizeof(sockaddr));
// 2. 发送数据,并接受服务端数据
char* send_info = {"How are you?"};
while(1) {
send(sock_client, send_info, strlen(send_info) + 1, 0);
printf("send: %s\n", send_info);
char recv_info[50];
recv(sock_client, recv_info, sizeof(recv_info), 0);
printf("receive: %s\n", recv_info);
}
// 3. 关闭客户端
close(sock_client);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main() {
/**
* 1. 创建服务端socket,并绑定相应ip和端口
* SOCK_STREAM对应的是TCP协议,安全可靠;SOCK_DGRAM是UDP协议,不可靠
* listen使得该进程可以接收socket的请求,成为一个服务端。对应的是客户端的connect。
*/
int sock_server = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(8888);
bind(sock_server, (struct sockaddr *)&server_addr, sizeof(server_addr));
listen(sock_server, 5);
// 2. 服务端接受客户端的请求
int socklen = sizeof(struct sockaddr_in);
sockaddr_in client_addr;
int sock_client = accept(sock_server, (struct sockaddr *)&client_addr,
(socklen_t *)&socklen);
printf("client %s has connnected\n", inet_ntoa(client_addr.sin_addr));
// 3. 同客户端连接,并接受数据
char buffer[50];
while (1) {
memset(buffer, 0, sizeof(buffer));
recv(sock_client, buffer, sizeof(buffer), 0);
printf("receive: %s\n", buffer);
strcpy(buffer, "I'm fine, thx!");
send(sock_client, buffer, strlen(buffer), 0);
printf("send : %s\n", buffer);
}
// 4. 关闭
close(sock_server);
close(sock_client);
return 0;
}
共享内存的实现有些麻烦,同样也是开辟一块共有内存进行读写,速度也很快,正常读写没啥问题,但是通信的话存在同步性的问题,就是没有管道的阻塞性。
mmap(Memory-mapped file support),内存映射文件支持,详细见python标准库。
内存映射文件在Unix和Windows上是不同的,但本质都需要提供一个打开的文件来提供文件描述符以进行更新。
import mmap
import contextlib
import time
with open("node1.dat", "w") as fout:
fout.write('\x00' * 1024)
i = 0
# node1
while True:
with open("node1.dat", "r+") as fout:
with contextlib.closing(mmap.mmap(fout.fileno(), 1024, access=mmap.ACCESS_WRITE)) as m_write:
m_write.seek(0)
i += 1
s = "node1: How are you?" + str(i)
s.rjust(1024, '\x00')
m_write.write(s.encode())
m_write.flush()
time.sleep(1)
import mmap
import contextlib
import time
import random
i = 0
# node2
while True:
with open('node1.dat', 'r') as fin:
with contextlib.closing(mmap.mmap(fin.fileno(), 0, access=mmap.ACCESS_READ)) as m:
s = m.read(1024)
s = s.decode()
print(s)
i += 1
print("node2: I'm fine, thx!" + str(i))
time.sleep(1)
除了mmap可以处理共享内存,multiprocessing
库同样可以处理,同时还有队列、管道等其他通讯方式,只是只找到python进程之间通讯的,没有跨语言的实现,参考一文读懂Python进程间通信的几种方式。
simple_python_cpp_communication
cd cpp/test/build
cmake .. && make -j4
# 终端1
python python/fifo_node1_test.py
# 终端2
cpp/test/build/fifo_node2_test
# 终端1
cpp/test/build/fifo_node1_test
# 终端2
cpp/test/build/fifo_node2_test
# 终端1
python python/fifo_node1_test.py
# 终端2
python python/fifo_node2_test.py
# 终端1
python python/socket_server.py
# 终端2
cpp/test/build/socket_clien_test
# 终端1
cpp/test/build/socket_server_test
# 终端2
cpp/test/build/socket_clien_test
# 终端1
python python/socket_server.py
# 终端2
python python/socket_client.py
# 终端1
python python/mmap_node1.py
# 终端2
python python/mmap_node2.py
# 终端1
cpp/test/build/sm_server
# 终端2
cpp/test/build/sm_client
LINUX学习——进程间通信方式(1):c++管道通信
Python进程间通信之共享内存:python的mmap共享内存通信,linux需要单独创建文件,不同于windows直接使用tagname标识一下就行,感觉不是很方便