windows下C++管道通信
在windows下,可通过Vs Studio中的C++ CMake创建管道通信的demo。
工程文件结构如下:
bash
pipe_communication_test
pipe_server.cpp
pipe_client.cpp
CMakeLists.txt
CMakePresets.json //使用Vs Studio创建CMake项目时,自动生成的文件
服务端"pipe_server.cpp"
cpp
#include <iostream>
#include <windows.h>
#include <ctime>
#include <conio.h>
#include <functional>
#include <thread>
#include <string>
#include <tchar.h>
using namespace std;
#define BUFSIZE 128
class Pipe_Server {
public:
Pipe_Server(std::string pipe_name, std::function<std::string(std::string)> callBackFun) {
pipe_name_ = "\\\\.\\Pipe\\";
pipe_name_ += pipe_name;
if (pipe_name == "") {
std::cout << "pipe name is empty" << std::endl;
return;
}
std::cout << "Create pipe server: " << pipe_name << std::endl;
callBackFun_ = callBackFun;
std::thread run_thread(std::bind(&Pipe_Server::run, this));
run_thread.detach();
}
~Pipe_Server() {}
private:
//待绑定的回调函数
std::function<std::string(std::string)> callBackFun_;
std::string pipe_name_;
WCHAR* toWChar(const char* c) {
WCHAR wszClassName[256];
memset(wszClassName, 0, sizeof(wszClassName));
MultiByteToWideChar(CP_ACP, 0, c, strlen(c) + 1, wszClassName,
sizeof(wszClassName) / sizeof(wszClassName[0]));
return wszClassName;
}
void run() {
while (1) {
HANDLE hPipe = CreateNamedPipe(pipe_name_.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES, 0, 0, NMPWAIT_WAIT_FOREVER, 0);
//waiting to be connected
if (ConnectNamedPipe(hPipe, NULL) != NULL) {
std::cout << "连接成功,开始发送数据" << std::endl;
//接收服务端发回的数据
BOOL fSuccess = false;
DWORD len = 0;
char buffer[BUFSIZE];
string recvData = "";
while (true) {
fSuccess = ReadFile(hPipe, buffer, BUFSIZE * sizeof(char), &len, NULL);
char buffer2[BUFSIZE + 1] = { 0 };
memcpy(buffer2, buffer, len);
recvData.append(buffer2);
if (!fSuccess || len < BUFSIZE)
break;
}
std::cout << "recv data: \n" << recvData.c_str() << std::endl;
std::string res_msg = callBackFun_(recvData);
DWORD dwWrite;
char* pStr = nullptr;
pStr = new char(res_msg.size() + 1); //存在内存泄露
strcpy(pStr, res_msg.c_str()); //将string转变成char*
if (!WriteFile(hPipe, pStr, strlen(pStr), &dwWrite, NULL)) {
std::cout << "write failed..." << std::endl;
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);//关闭管道
std::cout << "结束一次管道通信" << std::endl;
//delete pStr; //造成程序错误
break;
}
else {
std::cout << "send data: \n" << pStr << std::endl;
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);//关闭管道
//delete pStr; //造成程序错误
std::cout << "结束一次管道通信" << std::endl;
}
}
else {
std::cout << "pipe connect failed" << std::endl;
Sleep(1000);
}
}
}
};
std::string msgProcess(std::string msg) {
std::string return_msg = msg;
return_msg += " test";
std::cout << "process msg" << std::endl;
return return_msg;
}
int main() {
std::cout << "pipe server" << std::endl;
Pipe_Server pipe_server("pipe", std::bind(msgProcess, std::placeholders::_1));
while (1) {
Sleep(1000);
}
system("pause");
return 0;
}
客户端"pipe_client.h"
cpp
#include <iostream>
#include <windows.h>
#include <ctime>
#include <conio.h>
#define BUFSIZE 128
class Pipe_Client {
public:
Pipe_Client(std::string pipe_name) {
pipe_name_ = "\\\\.\\Pipe\\";
pipe_name_ += pipe_name;
if (pipe_name == "") {
//LOG(ERROR) << "pipe name is empty";
std::cout << "pipe name is empty" << std::endl;
return;
}
std::cout << "pipe name is: " << pipe_name << std::endl;
}
~Pipe_Client() {}
std::string sendAndGetMsg(std::string send_msg) {
if (WaitNamedPipe(pipe_name_.c_str(), NMPWAIT_WAIT_FOREVER) == FALSE) {
//LOG(INFO) << "EEEEEEEEE";
std::cout << "wait pipe failed" << std::endl;
return "";
}
//LOG(INFO) << "打开命名管道: " << pipe_name_;
std::cout << "打开命名管道: " << pipe_name_ << std::endl;
HANDLE hPipe = CreateFile(pipe_name_.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ((long)hPipe == -1) {
std::cout << "打开管道失败" << std::endl;
return "";
}
//发送数据
DWORD dwWrite;
static char* pStr = nullptr;
if (pStr != nullptr) {
delete pStr;
}
pStr = new char(send_msg.size() + 1);
strcpy(pStr, send_msg.c_str()); //将string转变成char*
if (!WriteFile(hPipe, pStr, strlen(pStr), &dwWrite, NULL)) {
std::cout << "write failed..." << std::endl << std::endl;
return "";
}
std::cout << "sent data: " << std::endl << pStr << std::endl << std::endl;
Sleep(400);
//接收服务端发回的数据
BOOL fSuccess = false;
DWORD len = 0;
char buffer[BUFSIZE];
std::string recvData = "";
while (true) {
fSuccess = ReadFile(hPipe, buffer, BUFSIZE * sizeof(char), &len, NULL);
char buffer2[BUFSIZE + 1] = { 0 };
memcpy(buffer2, buffer, len);
recvData.append(buffer2);
if (!fSuccess || len < BUFSIZE)
break;
}
std::cout << "recv data:" << std::endl << recvData.c_str() << std::endl << std::endl;
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
return recvData;
}
private:
std::string pipe_name_;
};
std::string msgProcess(std::string msg) {
std::string return_msg;
return return_msg;
}
int main() {
std::cout << "pipe client" << std::endl;
Pipe_Client pipe_client("pipe");
std::cout << "rec: " << pipe_client.sendAndGetMsg("qwer");
while (1) {
Sleep(1000);
}
system("pause");
return 0;
}
CMake文件"CMakeList.txt"
bash
# CMakeList.txt: create_process_test 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)
project ("pipe_communication_test")
add_executable(pipe_server pipe_server.cpp)
add_executable(pipe_client pipe_client.cpp)
注意事项
- pipe_server.cpp中存在内存泄漏的问题,暂时没有解决;
- 只能使用VsStudio的CMake进行编译,否则无法完成编译;