windows下C++管道通信

windows下C++管道通信

  在windows下,可通过Vs Studio中的C++ CMake创建管道通信的demo。
  工程文件结构如下:

pipe_communication_test
    pipe_server.cpp
    pipe_client.cpp
    CMakeLists.txt
    CMakePresets.json    //使用Vs Studio创建CMake项目时,自动生成的文件

服务端“pipe_server.cpp”

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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”

#include 
#include 
#include 
#include 

#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”

# 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)

注意事项

  1. pipe_server.cpp中存在内存泄漏的问题,暂时没有解决;
  2. 只能使用VsStudio的CMake进行编译,否则无法完成编译;

你可能感兴趣的:(windows,c++,管道通信)