命名管道简单封装
CNamedPipe.h
- #pragma once
- #include
- #include
- #include
-
- #pragma warning(disable:4200)
-
- class CNamedPipe
- {
- public:
- CNamedPipe();
-
- ~CNamedPipe();
-
- CNamedPipe(const CNamedPipe& r) = delete;
- CNamedPipe& operator = (const CNamedPipe& r) = delete;
-
- //
- // @brief: 创建命名管道
- // @param: lpName 管道名
- // @ret: bool true: 创建成功 false: 创建失败
- bool Create(LPCTSTR lpName);
-
- //
- // @brief: 等待客户端连接命名管道
- // @param: nTimeOut 超时等待(毫秒)
- // @ret: bool true: 连接成功 false: 连接失败
- bool WaitConnect(DWORD nTimeOut = INFINITE);
-
- //
- // @brief: 关闭由Create 创建的管道
- // @param: void
- // @ret: bool true: 关闭 成功 false: 关闭 失败
- bool Disconnect();
-
- //
- // @brief: 打开已存在的命名管道
- // @param: lpName 管道名
- // @ret: bool true: 打开成功 false: 打开失败
- bool Open(LPCTSTR lpName, DWORD nTimeOut = INFINITE);
-
- //
- // @brief: 管道是否有效
- // @param: void
- // @ret: bool true: 可用 false: 无效
- bool IsValid();
-
- //
- // @brief: 关闭管道
- // @param: void
- // @ret: void
- void Close(void);
-
- //
- // @brief: 从读取管道数据
- // @param: lpData 数据存放缓冲
- // @param: nSize 缓冲大小(字节)
- // @param: lpBytesRead 指向实际读取大小(字节)的指针
- // @param: nTimeOut 读取超时(毫秒)
- // @ret: bool true: 读取成功 false: 读取失败
- bool Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead = nullptr, DWORD nTimeOut = INFINITE);
-
- //
- // @brief: 向管道写入数据
- // @param: lpData 写入数据指针
- // @param: nSize 写入数据大小(字节)
- // @param: lpBytesWritten 指向实际写入大小(字节)的指针
- // @param: nTimeOut 写入超时(毫秒)
- // @ret: bool true: 写入成功 false: 写入失败
- bool Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten = nullptr, DWORD nTimeOut = INFINITE);
-
- private:
-
- //
- // @brief: 初始化对象占用
- // @param: void
- // @ret: void
- bool Initialize();
-
- //
- // @brief: 释放对象占用
- // @param: void
- // @ret: void
- void Uninitialize();
-
- private:
- HANDLE m_hNamedPipe = INVALID_HANDLE_VALUE;
- HANDLE m_hReadEvent = NULL;
- HANDLE m_hWriteEvent = NULL;
- LPVOID m_pBuffer = nullptr;
- bool m_bInit = false;
- bool m_bConnected = false;
- };
-
CNamedPipe.cpp
- #include "CNamedPipe.h"
- #include
- #include
-
- #define PIPE_NAME_PREFIX TEXT(R"(\\.\pipe\)") //管道前缀名
- #define PIPE_MAX_TIMEOUT (3000) //管道打开超时
- #define PIPE_BUF_MAX_SIZE (1024 * 1024) //管道发送缓冲大小(字节)
- #define PIPE_MAX_CONNECT (16) //IPC最大连接数
-
- typedef struct _PIPE_DATA
- {
- DWORD dwSize = 0;
- BYTE data[0];
- }PIPE_DATA, * PPIPE_DATA;
-
- CNamedPipe::CNamedPipe() :
- m_pBuffer(nullptr),
- m_hNamedPipe(INVALID_HANDLE_VALUE),
- m_hReadEvent(NULL),
- m_hWriteEvent(NULL),
- m_bConnected(false),
- m_bInit(false)
- {
- //初始化读写缓冲与事件句柄
- Initialize();
- }
-
- CNamedPipe::~CNamedPipe()
- {
- //释放读写缓冲与事件句柄
- Uninitialize();
- }
-
- bool CNamedPipe::Create(LPCTSTR lpName)
- {
- TCHAR szPipeName[MAX_PATH];
- SECURITY_ATTRIBUTES sa = { 0 };
- SECURITY_DESCRIPTOR sd = { 0 };
- bool isSuccess = false;
-
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = FALSE;
- sa.lpSecurityDescriptor = &sd;
-
- if (INVALID_HANDLE_VALUE != m_hNamedPipe)
- {
- return true;
- }
-
- //设置权限, 防止低权限进程不能打开高权限进程创建的管道
- (void)::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
- (void)::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
- (void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);
-
- do
- {
- m_hNamedPipe = ::CreateNamedPipe(
- szPipeName,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_MAX_CONNECT,
- PIPE_BUF_MAX_SIZE,
- PIPE_BUF_MAX_SIZE,
- PIPE_MAX_TIMEOUT,
- &sa
- );
-
- if (INVALID_HANDLE_VALUE == m_hNamedPipe)
- {
- break;
- }
-
- isSuccess = true;
-
- } while (false);
-
- if (!isSuccess)
- {
- this->Close();
- }
-
- return isSuccess;
- }
-
- bool CNamedPipe::Open(LPCTSTR lpName, DWORD nTimeOut/* = INFINITE*/)
- {
- TCHAR szPipeName[MAX_PATH] = { 0 };
- bool isSuccess = false;
-
- (void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);
-
- if (INVALID_HANDLE_VALUE != m_hNamedPipe)
- {
- return true;
- }
-
- ULONGLONG ullCurTick = ::GetTickCount64();
-
- do
- {
- m_hNamedPipe = ::CreateFile(
- szPipeName,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
- NULL
- );
-
- //管道句柄有效则终止循环
- if (INVALID_HANDLE_VALUE != m_hNamedPipe)
- {
- isSuccess = true;
- break;
- }
-
- //若错误原因不是因为所有管道范例都在使用中, 则退出循环
- if (ERROR_PIPE_BUSY != ::GetLastError())
- {
- break;
- }
-
- //等待命名管道的实例可用于连接
- if (::WaitNamedPipe(szPipeName, 1000))
- {
- continue;
- }
-
- //无限等待则不需要检查超时
- if (INFINITE == nTimeOut)
- {
- continue;
- }
-
- //执行操作超时则退出循环
- if (::GetTickCount64() - ullCurTick > nTimeOut)
- {
- break;
- }
-
- } while (INVALID_HANDLE_VALUE == m_hNamedPipe);
-
- if (!isSuccess)
- {
- this->Close();
- }
-
- return isSuccess;
- }
-
- bool CNamedPipe::WaitConnect(DWORD nTimeOut)
- {
- OVERLAPPED Overlapped = { 0 };
- bool isConnected = false;
-
- if (INVALID_HANDLE_VALUE == m_hNamedPipe)
- {
- return false;
- }
-
- Overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
- if (NULL == Overlapped.hEvent)
- {
- return false;
- }
-
- isConnected = ::ConnectNamedPipe(m_hNamedPipe, &Overlapped);
-
- if (!isConnected)
- {
- DWORD dwError = ::GetLastError();
-
- //管道关闭中
- if (ERROR_NO_DATA == dwError)
- {
- isConnected = false;
- }
-
- //操作处于挂起状态
- if (ERROR_IO_PENDING == dwError)
- {
- if (WAIT_OBJECT_0 == ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
- {
- isConnected = true;
- }
- }
-
- //管道已经连接
- if (ERROR_PIPE_CONNECTED == dwError)
- {
- isConnected = true;
- }
- }
-
- if (NULL != Overlapped.hEvent)
- {
- ::CloseHandle(Overlapped.hEvent);
- }
-
- m_bConnected = isConnected;
-
- return isConnected;
- }
-
- bool CNamedPipe::Disconnect()
- {
- if (INVALID_HANDLE_VALUE == m_hNamedPipe)
- {
- return false;
- }
-
- //参数句柄必须由 CreateNamedPipe 函数创建
- return ::DisconnectNamedPipe(m_hNamedPipe);
- }
-
- void CNamedPipe::Close()
- {
- if (INVALID_HANDLE_VALUE != m_hNamedPipe)
- {
- if (m_bConnected)
- {
- ::FlushFileBuffers(m_hNamedPipe);
- ::DisconnectNamedPipe(m_hNamedPipe);
- m_bConnected = false;
- }
- ::CloseHandle(m_hNamedPipe);
- m_hNamedPipe = INVALID_HANDLE_VALUE;
- }
- }
-
- bool CNamedPipe::IsValid()
- {
- return INVALID_HANDLE_VALUE != m_hNamedPipe;
- }
-
- bool CNamedPipe::Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead/* = nullptr*/, DWORD nTimeOut)
- {
- OVERLAPPED Overlapped = { 0 };
- Overlapped.hEvent = m_hReadEvent;
- DWORD dwBytesTransferred = 0;
- bool isSuccess = false;
-
- if (nullptr == m_pBuffer ||
- nullptr == lpData ||
- 0 == nSize ||
- nSize > PIPE_BUF_MAX_SIZE
- )
- {
- return false;
- }
-
- PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;
- if (!::ReadFile(m_hNamedPipe, &pData->dwSize, sizeof(PIPE_DATA), NULL, &Overlapped))
- {
- //管道已结束
- if (ERROR_BROKEN_PIPE == ::GetLastError())
- {
- return false;
- }
-
- if (ERROR_IO_PENDING != ::GetLastError())
- {
- return false;
- }
-
- if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
- {
- return false;
- }
- }
-
- if (pData->dwSize > PIPE_BUF_MAX_SIZE)
- {
- return false;
- }
-
- if (!::ReadFile(m_hNamedPipe, pData->data, pData->dwSize, NULL, &Overlapped))
- {
- if (ERROR_IO_PENDING != ::GetLastError())
- {
- return false;
- }
-
- if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
- {
- return false;
- }
- }
-
- if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true))
- {
- isSuccess = true;
- if (lpBytesRead)
- {
- *lpBytesRead = dwBytesTransferred;
- }
- }
-
- if (isSuccess)
- {
- if (nSize < pData->dwSize)
- {
- ::memcpy_s(lpData, nSize, pData->data, nSize);
- }
- else
- {
- ::memcpy_s(lpData, nSize, pData->data, pData->dwSize);
- }
- }
-
- return isSuccess;
- }
-
- bool CNamedPipe::Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten/* = nullptr*/, DWORD nTimeOut)
- {
- OVERLAPPED Overlapped = { 0 };
- Overlapped.hEvent = m_hWriteEvent;
- DWORD dwBytesTransferred = 0;
- bool isSuccess = false;
-
- if (nullptr == m_pBuffer ||
- nullptr == lpData ||
- 0 == nSize ||
- nSize > PIPE_BUF_MAX_SIZE
- )
- {
- return false;
- }
-
- PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;
- DWORD dwBytesToWrite = nSize + sizeof(PIPE_DATA);
- pData->dwSize = nSize;
- ::memcpy_s(pData->data, PIPE_BUF_MAX_SIZE, lpData, nSize);
-
- if (::WriteFile(m_hNamedPipe, pData, dwBytesToWrite, NULL, &Overlapped))
- {
- return true;
- }
-
- //管道正在被关闭
- if (ERROR_NO_DATA == ::GetLastError())
- {
- return false;
- }
-
- //管道已结束
- if (ERROR_BROKEN_PIPE == ::GetLastError())
- {
- return false;
- }
-
- //重叠
- if (ERROR_IO_PENDING != ::GetLastError())
- {
- return false;
- }
-
- if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
- {
- return false;
- }
-
- if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true))
- {
- isSuccess = true;
- if (lpBytesWritten)
- {
- *lpBytesWritten = dwBytesTransferred;
- }
- }
-
- return isSuccess;
- }
-
- bool CNamedPipe::Initialize()
- {
- bool isSuccess = false;
-
- if (m_bInit)
- {
- return true;
- }
-
- do
- {
- if (nullptr == m_pBuffer)
- {
- m_pBuffer = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUF_MAX_SIZE + sizeof(PIPE_DATA));
- }
-
- if (nullptr == m_pBuffer)
- {
- break;
- }
-
- if (NULL == m_hReadEvent)
- {
- m_hReadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
- }
-
- if (NULL == m_hReadEvent)
- {
- break;
- }
-
- if (NULL == m_hWriteEvent)
- {
- m_hWriteEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
- }
-
- if (NULL == m_hWriteEvent)
- {
- break;
- }
-
- isSuccess = true;
-
- } while (false);
-
- if (!isSuccess)
- {
- Uninitialize();
- }
-
- m_bInit = isSuccess;
-
- return m_bInit;
- }
-
- void CNamedPipe::Uninitialize()
- {
- if (!m_bInit)
- {
- return;
- }
-
- //关闭管道
- this->Close();
-
- //释放读写缓冲
- if (nullptr != m_pBuffer)
- {
- ::HeapFree(::GetProcessHeap(), 0, m_pBuffer);
- m_pBuffer = nullptr;
- }
-
- //关闭事件
- if (m_hReadEvent)
- {
- CloseHandle(m_hReadEvent);
- m_hReadEvent = NULL;
- }
-
- if (m_hWriteEvent)
- {
- CloseHandle(m_hWriteEvent);
- m_hWriteEvent = NULL;
- }
-
- m_bInit = false;
- }
main.cpp
- #include
- #include "Utils/CNamedPipe.h"
- #include
- #include
-
- int main()
- {
- std::promise<bool> p;
- std::future<bool> f = p.get_future();
-
- std::thread(
- [&p]()
- {
- static char szBuf[1024 * 64] = { 0 };
- CNamedPipe pipe;
- if (!pipe.Create(_T("FlameCyclone")))
- {
- std::cout << "Create failed!" << std::endl;
- p.set_value(false);
- return;
- }
-
- p.set_value(true);
-
- while (true)
- {
- if (!pipe.WaitConnect())
- {
- std::cout << "WaitConnect failed!" << std::endl;
- break;
- }
-
- while (true)
- {
- bool isSuccess = pipe.Read(szBuf, sizeof(szBuf));
- if (isSuccess)
- {
- std::cout << "recv: " << szBuf << std::endl;
- }
-
- //另一端断开则重新等待连接
- if (ERROR_BROKEN_PIPE == ::GetLastError())
- {
- pipe.Disconnect();
- if (!pipe.WaitConnect())
- {
- std::cout << "WaitConnect failed!" << std::endl;
- return;
- }
- }
- }
- }
- }
- ).detach();
-
- if (!f.get())
- {
- return -1;
- }
-
- CNamedPipe pipe;
- if (!pipe.Open(_T("FlameCyclone"), 5000))
- {
- std::cout << "Open failed!" << std::endl;
- return -1;
- }
-
- std::string strMsg;
-
- while (true)
- {
- std::cin >> strMsg;
- std::cout << "send: " << strMsg << std::endl;
-
- if (!pipe.Write(strMsg.c_str(), strMsg.size() + 1))
- {
- std::cout << "Write failed!" << std::endl;
- break;
- }
- }
-
- system("pause");
- return 0;
- }