因项目需求,需要实现python与c++间的通信。由于代码都在本地,因此采用管道通信的方式。
管道是用于连接读/写进程的共享文件,pipe文件,本质上是内存中固定大小的缓冲区。管道通信的特点如下:
1.以流的形式读写:未满不读,已满不写,未空不写,已空不读,读后删除
2.同一时段只能单向通信,属于半双工通信
3.以先进先出(FIFO)方式组织数据传输
4.通过系统调用read()/write()函数进行读写操作
下面是代码demo:
1.python创建管道,c++先写再读,python先读再写
python端代码:
import torch
import win32file
import win32pipe
import struct
from alog import MyAdd
class Mypipe():
def __init__(self):
# 数据内容
self.end_context = None
# 初始化模型
self.model = torch.jit.load("model.pt")
def pipe_init(self):
# 创建管道
self.python_pipe = win32pipe.CreateNamedPipe(r"\\.\\Pipe\\JUECE1-1",
win32pipe.PIPE_ACCESS_DUPLEX,
win32pipe.PIPE_TYPE_MESSAGE|win32pipe.PIPE_WAIT|win32pipe.PIPE_READMODE_MESSAGE,
win32pipe.PIPE_UNLIMITED_INSTANCES,
65536,
65536,
500,
None)
def pipe_connect(self):
win32pipe.ConnectNamedPipe(self.python_pipe, None)
print("python 管道链接成功!")
def pipe_run(self):
print("管道开始运行!")
while(1):
# 计算格式大小
formats = "<" + 'f' + 'd' * 10 + 'i' + "I" + 'd' + 'f'*6
size = struct.calcsize(formats)
print(size)
res = win32file.ReadFile(self.python_pipe, size, None)
res = res[1]
res = struct.unpack(formats, res)
print("接收到的数据:")
print(res[0], res[1], res[2], res[3], res[4],
res[5], res[6], res[7], res[8], res[9],
res[10], res[11],
res[12], res[13], res[14], res[15],
res[16], res[17], res[18], res[19], )
# 算法一:调用pt模型
res = res[:10]
tensor_data = torch.tensor(res, dtype=torch.float32)
res_algo_1 = self.model(tensor_data).detach().numpy()
# 算法二:调用普通算法
res_algo_2 = MyAdd(res[0], res[1])
res_list = []
for i in res_algo_1:
res_list.append(i)
res_list.append(res_algo_2)
print("计算出的数据:")
print(res_list[0], res_list[1],res_list[2],res_list[3],res_list[4],res_list[5])
self.end_context = struct.pack("f"*6, *res_list)
win32file.WriteFile(self.python_pipe, self.end_context)
def pipe_close(self):
print("python 管道关闭!")
win32pipe.DisconnectNamedPipe(self.python_pipe)
if __name__ == "__main__":
mypipe = Mypipe()
mypipe.pipe_init()
mypipe.pipe_connect()
mypipe.pipe_run()
mypipe.pipe_close()
c++端代码:
#include
#include
#include
#include
//发送数据的字节数
#define BUF_SIZE 2
#define RUNTIME 10
#define NODENUM 3
//字节对齐
#pragma pack(1)
using namespace std;
struct MMF
{
unsigned int num;
double kkk;
float mmf;
float mmf1;
float mmf2;
float mmf3;
float mmf4;
float mmf5;
};
struct StructReq
{
float params2;
double params[10];
int params3;
MMF mmf;
};
struct StructRes
{
float params[3];
float result[3];
};
int main()
{
DWORD rLen = 0;
DWORD wLen = 0;
HANDLE hPipe;
string pName;
LPCWSTR wpName;
StructRes res;
StructReq req;
req.params2 = 1.2;
req.params3 = 4;
for (int j = 0;j < 10;j++) {
req.params[j] = 1;
}
req.mmf.num = 400;
req.mmf.kkk = 4;
req.mmf.mmf = 4.5;
req.mmf.mmf1 = 5.5;
req.mmf.mmf2 = 5.6;
req.mmf.mmf3 = 5.7;
req.mmf.mmf4 = 5.8;
req.mmf.mmf5 = 5.9;
if (!WaitNamedPipe(TEXT("\\\\.\\Pipe\\JUECE1-1"), NMPWAIT_WAIT_FOREVER)) {
cout << "Connect NP Failed!" << endl;
return 1;
}
hPipe = CreateFile(
TEXT("\\\\.\\Pipe\\JUECE1-1"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == hPipe)
{
cout << "Open Pipe Failed!" << endl;
return 2;
}
WriteFile(hPipe, (byte*)&req, sizeof(StructReq), &wLen, 0);
ReadFile(hPipe, (byte*)&res, sizeof(StructRes), &rLen, NULL);
cout << res.params[0] << "\t" << res.params[1] << "\t" << res.params[2] << "\t" << res.result[0] << "\t"
<< res.result[1] << "\t" << res.result[2] << endl;
system("pause");
return 0;
}
2.c++创建管道,c++先写再读,python先读再写
python端代码:
import torch
import win32file
import win32pipe
import struct
from alog import MyAdd
class Mypipe():
def __init__(self):
# 数据内容
self.end_context = None
# 初始化模型
self.model = torch.jit.load("model.pt")
def pipe_init(self):
# 创建管道文件
PIPE_NAME = r"\\.\Pipe\mypipe"
self.python_pipe = win32file.CreateFile(
PIPE_NAME,
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
win32file.FILE_SHARE_WRITE, None,
win32file.OPEN_EXISTING, 0, None)
def pipe_run(self):
print("管道开始运行!")
while(1):
formats = "<" + 'f' + 'd' * 10 + 'i' + "I" + 'd' + 'f'*6
# formats = "<" + 'f' + 's'*10 + 'i'
size = struct.calcsize(formats)
print(size)
res = win32file.ReadFile(self.python_pipe, size, None)
res = res[1]
res = struct.unpack(formats, res)
print("接收到的数据:")
print(res[0], res[1], res[2], res[3], res[4],
res[5], res[6], res[7], res[8], res[9],
res[10], res[11],
res[12], res[13], res[14], res[15],
res[16], res[17], res[18], res[19], )
# 算法一:调用pt模型
res = res[:10]
tensor_data = torch.tensor(res, dtype=torch.float32)
res_algo_1 = self.model(tensor_data).detach().numpy()
# 算法二:调用普通算法
res_algo_2 = MyAdd(res[0], res[1])
res_list = []
for i in res_algo_1:
res_list.append(i)
res_list.append(res_algo_2)
print("计算出的数据:")
print(res_list[0], res_list[1],res_list[2],res_list[3],res_list[4],res_list[5])
self.end_context = struct.pack("f"*6, *res_list)
win32file.WriteFile(self.python_pipe, self.end_context)
if __name__ == "__main__":
mypipe = Mypipe()
mypipe.pipe_init()
mypipe.pipe_run()
c++端代码:
int main()
{
//cpp创建管道
printf("创建命名管道并等待连接\n");
char pipeName[] = "\\\\.\\Pipe\\mypipe";
HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES, 0, 0, NMPWAIT_WAIT_FOREVER, 0);
StructRes res;
StructReq req;
DWORD rLen = 0;
DWORD wLen = 0;
cout << "Client Started!" << endl;
//waiting to be connected
if (ConnectNamedPipe(hPipe, NULL) != NULL)
{
printf("连接成功,开始发送数据\n");
if (!WriteFile(hPipe, (byte*)&req, sizeof(StructReq), &wLen, 0))
{
cout << "Request Failed!" << endl;
}
else {
if (!ReadFile(hPipe, (byte*)&res, sizeof(StructRes), &rLen, NULL))
{
cout << "Response Failede!" << endl;
}
else {
cout << res.params[0] <<"\t"<< res.params[1] << "\t" << res.params[2] << "\t" << res.result[0] << "\t"
<< res.result[1] << "\t" << res.result[2] << endl;
}
}
}
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);//关闭管道
printf("关闭管道\n");
system("pause");
return 0;
}
注意事项:
1.c++端要加pragma pack(1),按一字节对齐
2.python端采用小端对齐的方式获取字节数