进程间通信(封装级别)、可拿入项目中直接使用!!!!!
**
PipeCS.h文件
**
#pragma once
#include <Windows.h>
#include <string>
#include <thread>
#include <iostream>
#include <atomic>
#include <iostream>
class CPipeBase
{
public:
CPipeBase() = default;
virtual ~CPipeBase() = default;
typedef std::function<void(const std::string &szMsg)> TMessageHandler;
protected:
bool ReadPipe(HANDLE hNamedPipe, std::string &szMsg);
bool WritePipe(HANDLE hNamedPipe, const std::string &szMsg);
};
class CPipeServer : public CPipeBase
{
public:
CPipeServer(const std::string &szPipeName, TMessageHandler fnMsgHandler);
CPipeServer(const CPipeServer &Other) = delete;
CPipeServer(CPipeServer &&Other) = delete;
~CPipeServer();
CPipeServer& operator=(const CPipeServer &Other) = delete;
CPipeServer& operator=(CPipeServer &&Other) = delete;
void Run();
void Stop();
bool SendMsg(const std::string &szMsg);
private:
bool ConnectClient();
void DisconnectClient();
bool CreatePipeInstance(const std::string &szPipeName, HANDLE &hPipeInstance);
void Close();
private:
std::string m_szPipeName;
TMessageHandler m_fnMsgHandler;
HANDLE m_hNamedPipeR;
HANDLE m_hNamedPipeW;
};
class CPipeClient : public CPipeBase
{
public:
CPipeClient(const std::string &szPipeName, TMessageHandler fnMsgHandler);
CPipeClient(const CPipeClient &Other) = delete;
CPipeClient(CPipeClient &&Other) = delete;
~CPipeClient();
CPipeClient& operator=(const CPipeClient &Other) = delete;
CPipeClient& operator=(CPipeClient &&Other) = delete;
bool IsConnected() const;
bool Connect(unsigned int nTimeoutSeconds);
void Disconnect();
bool SendMsg(const std::string &szMsg);
protected:
bool SetMessageMode(HANDLE hNamedPipe);
void ReadThreadProc();
private:
std::string m_szPipeName;
HANDLE m_hNamedPipeW;
HANDLE m_hNamedPipeR;
// 消息读取线程
std::atomic_bool m_bThreadRun = false;
std::thread m_ReadThread;
TMessageHandler m_fnMsgHandler;
};
**
PipeCS.cpp文件
**
#include "PipeCS.h"
#define PIPE_BUF_SIZE 1024
bool CPipeBase::WritePipe(HANDLE hNamedPipe, const std::string &szMsg)
{
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
std::cout << "the pipe is invalid." << std::endl;
return false;
}
DWORD dwWritedBytes = 0;
DWORD dwTotalBytes = szMsg.size();
DWORD dwSentBytes = 0;
BOOL bResult = FALSE;
do
{
bResult = ::WriteFile(hNamedPipe, &szMsg[dwSentBytes], dwTotalBytes - dwSentBytes, &dwWritedBytes, NULL);
if (!bResult || dwWritedBytes == 0)
{
std::cout << "write message to pipe error: " << ::GetLastError() << std::endl;
return false;
}
dwSentBytes += dwWritedBytes;
} while (dwSentBytes < dwTotalBytes);
return true;
}
bool CPipeBase::ReadPipe(HANDLE hNamedPipe, std::string &szMsg)
{
szMsg.clear();
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
std::cout << "the pipe is invalid." << std::endl;
return false;
}
bool bResult = false;
DWORD dwError = ERROR_SUCCESS;
DWORD dwReadBytes = 0;
CHAR ReadBuf[PIPE_BUF_SIZE] = { 0 };
bool bReadMore = false;
do
{
if (::ReadFile(hNamedPipe, ReadBuf, PIPE_BUF_SIZE, &dwReadBytes, NULL))
{
// 读成功,跳出
szMsg.append(ReadBuf, dwReadBytes);
bResult = true;
break;
}
dwError = ::GetLastError();
if (dwError == ERROR_MORE_DATA)
{
// 没有读完,继续读
szMsg.append(ReadBuf, dwReadBytes);
bReadMore = true;
continue;
}
// 其它错误,不再继续读
bReadMore = false;
if (dwError == ERROR_BROKEN_PIPE)
{
std::cout << "the pipe has disconnected." << std::endl;
}
else
{
std::cout << "read message from pipe error: " << dwError << std::endl;
}
} while (bReadMore);
return bResult;
}
CPipeServer::CPipeServer(const std::string &szPipeName, TMessageHandler fnMsgHandler) :
m_szPipeName(szPipeName), m_fnMsgHandler(fnMsgHandler)
{
m_hNamedPipeR = INVALID_HANDLE_VALUE;
m_hNamedPipeW = INVALID_HANDLE_VALUE;
}
CPipeServer::~CPipeServer()
{
Close();
}
void CPipeServer::Run()
{
std::cout << "pipe server will start." << std::endl;
std::string szMsg;
while (ConnectClient())
{
while (ReadPipe(m_hNamedPipeR, szMsg))
{
std::cout << "recv message success: " << szMsg;
if (m_fnMsgHandler)
{
m_fnMsgHandler(szMsg);
}
}
DisconnectClient();
}
Close();
std::cout << "pipe server will exit." << std::endl;
}
void CPipeServer::Stop()
{
Close();
}
bool CPipeServer::SendMsg(const std::string &szMsg)
{
std::cout << "send message: " << szMsg << std::endl;
bool bSuccess = WritePipe(m_hNamedPipeW, szMsg);
std::cout << "send message " << (bSuccess ? "success." : "failed.") << std::endl;
return bSuccess;
}
bool CPipeServer::ConnectClient()
{
if (m_szPipeName.empty())
{
std::cout << "the pipe name is empty." << std::endl;
return false;
}
std::string szFullName("\\\\.\\pipe\\");
szFullName += m_szPipeName;
std::cout << "create pipe server: " << m_szPipeName << std::endl;
if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
{
if (!CreatePipeInstance(szFullName, m_hNamedPipeR))
{
std::cout << "create pipe server for read failed." << std::endl;
return false;
}
std::cout << "create pipe server for read ok." << std::endl;
}
std::cout << "wait for the client to connect read ..." << std::endl;
if (!::ConnectNamedPipe(m_hNamedPipeR, NULL))
{
DWORD dwError = ::GetLastError();
if (dwError != ERROR_PIPE_CONNECTED)
{
std::cout << "wait for the client to connect read error: " << dwError << std::endl;
return false;
}
}
std::cout << "client is connected." << std::endl;
if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
{
if (!CreatePipeInstance(szFullName, m_hNamedPipeW))
{
std::cout << "create pipe server for write failed." << std::endl;
return false;
}
std::cout << "create pipe server for write ok." << std::endl;
}
std::cout << "wait for the client to connect write ..." << std::endl;
if (!::ConnectNamedPipe(m_hNamedPipeW, NULL))
{
DWORD dwError = ::GetLastError();
if (dwError != ERROR_PIPE_CONNECTED)
{
std::cout << "wait for the client to connect write error: " << dwError << std::endl;
return false;
}
}
std::cout << "connect pipe client success." << std::endl;
return true;
}
void CPipeServer::DisconnectClient()
{
if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
{
::DisconnectNamedPipe(m_hNamedPipeR);
}
if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
{
::DisconnectNamedPipe(m_hNamedPipeW);
}
}
bool CPipeServer::CreatePipeInstance(const std::string &szPipeName, HANDLE &hPipeInstance)
{
hPipeInstance = ::CreateNamedPipeA(szPipeName.c_str(),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
2,
PIPE_BUF_SIZE,
PIPE_BUF_SIZE,
0,
NULL);
if (hPipeInstance == INVALID_HANDLE_VALUE)
{
std::cout << "create pipe server error: " << ::GetLastError() << std::endl;
return false;
}
return true;
}
void CPipeServer::Close()
{
if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hNamedPipeR);
m_hNamedPipeR = INVALID_HANDLE_VALUE;
}
if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hNamedPipeW);
m_hNamedPipeW = INVALID_HANDLE_VALUE;
}
}
//
//
CPipeClient::CPipeClient(const std::string &szPipeName, TMessageHandler fnMsgHandler) :
m_szPipeName(szPipeName), m_fnMsgHandler(fnMsgHandler)
{
m_hNamedPipeW = INVALID_HANDLE_VALUE;
m_hNamedPipeR = INVALID_HANDLE_VALUE;
}
CPipeClient::~CPipeClient()
{
Disconnect();
}
bool CPipeClient::IsConnected() const
{
return (m_hNamedPipeW != INVALID_HANDLE_VALUE && m_hNamedPipeR != INVALID_HANDLE_VALUE);
}
bool CPipeClient::Connect(unsigned int nTimeoutSeconds)
{
if (IsConnected())
{
std::cout << "the pipe server is connected." << std::endl;
return true;
}
if (m_szPipeName.empty())
{
std::cout << "the pipe server name is empty." << std::endl;
return false;
}
std::string szFullName("\\\\.\\pipe\\");
szFullName += m_szPipeName;
std::cout << "connect to pipe server: " << m_szPipeName << " in " << nTimeoutSeconds << "s." << std::endl;
int64_t nTimeoutMs = nTimeoutSeconds * 1000;
DWORD dwError = ERROR_SUCCESS;
do
{
// 先连接写管道,再连接读管道
if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
{
m_hNamedPipeW = ::CreateFileA(szFullName.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (m_hNamedPipeW == INVALID_HANDLE_VALUE)
{
dwError = ::GetLastError();
}
else
{
SetMessageMode(m_hNamedPipeW);
}
}
else if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
{
m_hNamedPipeR = ::CreateFileA(szFullName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (m_hNamedPipeR == INVALID_HANDLE_VALUE)
{
dwError = ::GetLastError();
}
else
{
SetMessageMode(m_hNamedPipeR);
std::cout << "connect to pipe server ok." << std::endl;
m_bThreadRun = true;
m_ReadThread = std::thread(&CPipeClient::ReadThreadProc, this);
return true;
}
}
if (nTimeoutSeconds == 0)
{
std::cout << "connect to pipe server error: " << dwError << std::endl;
break;
}
if (nTimeoutMs <= 0)
{
std::cout << "connect to pipe server timeout: " << dwError << std::endl;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nTimeoutMs -= 100;
} while (true);
return false;
}
void CPipeClient::Disconnect()
{
if (m_hNamedPipeW != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hNamedPipeW);
m_hNamedPipeW = INVALID_HANDLE_VALUE;
}
if (m_hNamedPipeR != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hNamedPipeR);
m_hNamedPipeR = INVALID_HANDLE_VALUE;
}
m_bThreadRun = false;
if (m_ReadThread.joinable())
{
m_ReadThread.join();
}
}
bool CPipeClient::SendMsg(const std::string &szMsg)
{
bool bSuccess = false;
std::cout << "send message: " << szMsg << std::endl;
if (m_bThreadRun)
{
bSuccess = WritePipe(m_hNamedPipeW, szMsg);
}
std::cout << "send message " << (bSuccess ? "success." : "failed.") << std::endl;
return bSuccess;
}
bool CPipeClient::SetMessageMode(HANDLE hNamedPipe)
{
// 检查是否为消息模式
DWORD dwMode = 0;
if (!::GetNamedPipeHandleStateA(hNamedPipe, &dwMode, NULL, NULL, NULL, NULL, 0))
{
std::cout << "query the state of server error: " << ::GetLastError() << std::endl;
return false;
}
if (dwMode != PIPE_READMODE_MESSAGE)
{
dwMode = PIPE_READMODE_MESSAGE;
if (!::SetNamedPipeHandleState(hNamedPipe, &dwMode, NULL, NULL))
{
std::cout << "change to message-read mode error: " << ::GetLastError() << std::endl;
return false;
}
}
std::cout << "change to message-read mode ok." << std::endl;
return true;
}
void CPipeClient::ReadThreadProc()
{
std::cout << "read message thread begin." << std::endl;
while (m_bThreadRun)
{
std::string szMsg;
if (!ReadPipe(m_hNamedPipeR, szMsg))
{
m_bThreadRun = false;
break;
}
if (szMsg.empty())
{
continue;
}
if (m_fnMsgHandler)
{
m_fnMsgHandler(szMsg);
}
}
std::cout << "read message thread end." << std::endl;
}