• Win32 命名管道


    命名管道简单封装

     

    CNamedPipe.h

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #pragma warning(disable:4200)
    6. class CNamedPipe
    7. {
    8. public:
    9. CNamedPipe();
    10. ~CNamedPipe();
    11. CNamedPipe(const CNamedPipe& r) = delete;
    12. CNamedPipe& operator = (const CNamedPipe& r) = delete;
    13. //
    14. // @brief: 创建命名管道
    15. // @param: lpName 管道名
    16. // @ret: bool true: 创建成功 false: 创建失败
    17. bool Create(LPCTSTR lpName);
    18. //
    19. // @brief: 等待客户端连接命名管道
    20. // @param: nTimeOut 超时等待(毫秒)
    21. // @ret: bool true: 连接成功 false: 连接失败
    22. bool WaitConnect(DWORD nTimeOut = INFINITE);
    23. //
    24. // @brief: 关闭由Create 创建的管道
    25. // @param: void
    26. // @ret: bool true: 关闭 成功 false: 关闭 失败
    27. bool Disconnect();
    28. //
    29. // @brief: 打开已存在的命名管道
    30. // @param: lpName 管道名
    31. // @ret: bool true: 打开成功 false: 打开失败
    32. bool Open(LPCTSTR lpName, DWORD nTimeOut = INFINITE);
    33. //
    34. // @brief: 管道是否有效
    35. // @param: void
    36. // @ret: bool true: 可用 false: 无效
    37. bool IsValid();
    38. //
    39. // @brief: 关闭管道
    40. // @param: void
    41. // @ret: void
    42. void Close(void);
    43. //
    44. // @brief: 从读取管道数据
    45. // @param: lpData 数据存放缓冲
    46. // @param: nSize 缓冲大小(字节)
    47. // @param: lpBytesRead 指向实际读取大小(字节)的指针
    48. // @param: nTimeOut 读取超时(毫秒)
    49. // @ret: bool true: 读取成功 false: 读取失败
    50. bool Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead = nullptr, DWORD nTimeOut = INFINITE);
    51. //
    52. // @brief: 向管道写入数据
    53. // @param: lpData 写入数据指针
    54. // @param: nSize 写入数据大小(字节)
    55. // @param: lpBytesWritten 指向实际写入大小(字节)的指针
    56. // @param: nTimeOut 写入超时(毫秒)
    57. // @ret: bool true: 写入成功 false: 写入失败
    58. bool Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten = nullptr, DWORD nTimeOut = INFINITE);
    59. private:
    60. //
    61. // @brief: 初始化对象占用
    62. // @param: void
    63. // @ret: void
    64. bool Initialize();
    65. //
    66. // @brief: 释放对象占用
    67. // @param: void
    68. // @ret: void
    69. void Uninitialize();
    70. private:
    71. HANDLE m_hNamedPipe = INVALID_HANDLE_VALUE;
    72. HANDLE m_hReadEvent = NULL;
    73. HANDLE m_hWriteEvent = NULL;
    74. LPVOID m_pBuffer = nullptr;
    75. bool m_bInit = false;
    76. bool m_bConnected = false;
    77. };

    CNamedPipe.cpp

    1. #include "CNamedPipe.h"
    2. #include
    3. #include
    4. #define PIPE_NAME_PREFIX TEXT(R"(\\.\pipe\)") //管道前缀名
    5. #define PIPE_MAX_TIMEOUT (3000) //管道打开超时
    6. #define PIPE_BUF_MAX_SIZE (1024 * 1024) //管道发送缓冲大小(字节)
    7. #define PIPE_MAX_CONNECT (16) //IPC最大连接数
    8. typedef struct _PIPE_DATA
    9. {
    10. DWORD dwSize = 0;
    11. BYTE data[0];
    12. }PIPE_DATA, * PPIPE_DATA;
    13. CNamedPipe::CNamedPipe() :
    14. m_pBuffer(nullptr),
    15. m_hNamedPipe(INVALID_HANDLE_VALUE),
    16. m_hReadEvent(NULL),
    17. m_hWriteEvent(NULL),
    18. m_bConnected(false),
    19. m_bInit(false)
    20. {
    21. //初始化读写缓冲与事件句柄
    22. Initialize();
    23. }
    24. CNamedPipe::~CNamedPipe()
    25. {
    26. //释放读写缓冲与事件句柄
    27. Uninitialize();
    28. }
    29. bool CNamedPipe::Create(LPCTSTR lpName)
    30. {
    31. TCHAR szPipeName[MAX_PATH];
    32. SECURITY_ATTRIBUTES sa = { 0 };
    33. SECURITY_DESCRIPTOR sd = { 0 };
    34. bool isSuccess = false;
    35. sa.nLength = sizeof(sa);
    36. sa.bInheritHandle = FALSE;
    37. sa.lpSecurityDescriptor = &sd;
    38. if (INVALID_HANDLE_VALUE != m_hNamedPipe)
    39. {
    40. return true;
    41. }
    42. //设置权限, 防止低权限进程不能打开高权限进程创建的管道
    43. (void)::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
    44. (void)::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
    45. (void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);
    46. do
    47. {
    48. m_hNamedPipe = ::CreateNamedPipe(
    49. szPipeName,
    50. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
    51. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
    52. PIPE_MAX_CONNECT,
    53. PIPE_BUF_MAX_SIZE,
    54. PIPE_BUF_MAX_SIZE,
    55. PIPE_MAX_TIMEOUT,
    56. &sa
    57. );
    58. if (INVALID_HANDLE_VALUE == m_hNamedPipe)
    59. {
    60. break;
    61. }
    62. isSuccess = true;
    63. } while (false);
    64. if (!isSuccess)
    65. {
    66. this->Close();
    67. }
    68. return isSuccess;
    69. }
    70. bool CNamedPipe::Open(LPCTSTR lpName, DWORD nTimeOut/* = INFINITE*/)
    71. {
    72. TCHAR szPipeName[MAX_PATH] = { 0 };
    73. bool isSuccess = false;
    74. (void)::StringCchPrintf(szPipeName, _countof(szPipeName), TEXT("%s%s"), PIPE_NAME_PREFIX, lpName);
    75. if (INVALID_HANDLE_VALUE != m_hNamedPipe)
    76. {
    77. return true;
    78. }
    79. ULONGLONG ullCurTick = ::GetTickCount64();
    80. do
    81. {
    82. m_hNamedPipe = ::CreateFile(
    83. szPipeName,
    84. GENERIC_READ | GENERIC_WRITE,
    85. 0,
    86. NULL,
    87. OPEN_EXISTING,
    88. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
    89. NULL
    90. );
    91. //管道句柄有效则终止循环
    92. if (INVALID_HANDLE_VALUE != m_hNamedPipe)
    93. {
    94. isSuccess = true;
    95. break;
    96. }
    97. //若错误原因不是因为所有管道范例都在使用中, 则退出循环
    98. if (ERROR_PIPE_BUSY != ::GetLastError())
    99. {
    100. break;
    101. }
    102. //等待命名管道的实例可用于连接
    103. if (::WaitNamedPipe(szPipeName, 1000))
    104. {
    105. continue;
    106. }
    107. //无限等待则不需要检查超时
    108. if (INFINITE == nTimeOut)
    109. {
    110. continue;
    111. }
    112. //执行操作超时则退出循环
    113. if (::GetTickCount64() - ullCurTick > nTimeOut)
    114. {
    115. break;
    116. }
    117. } while (INVALID_HANDLE_VALUE == m_hNamedPipe);
    118. if (!isSuccess)
    119. {
    120. this->Close();
    121. }
    122. return isSuccess;
    123. }
    124. bool CNamedPipe::WaitConnect(DWORD nTimeOut)
    125. {
    126. OVERLAPPED Overlapped = { 0 };
    127. bool isConnected = false;
    128. if (INVALID_HANDLE_VALUE == m_hNamedPipe)
    129. {
    130. return false;
    131. }
    132. Overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
    133. if (NULL == Overlapped.hEvent)
    134. {
    135. return false;
    136. }
    137. isConnected = ::ConnectNamedPipe(m_hNamedPipe, &Overlapped);
    138. if (!isConnected)
    139. {
    140. DWORD dwError = ::GetLastError();
    141. //管道关闭中
    142. if (ERROR_NO_DATA == dwError)
    143. {
    144. isConnected = false;
    145. }
    146. //操作处于挂起状态
    147. if (ERROR_IO_PENDING == dwError)
    148. {
    149. if (WAIT_OBJECT_0 == ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
    150. {
    151. isConnected = true;
    152. }
    153. }
    154. //管道已经连接
    155. if (ERROR_PIPE_CONNECTED == dwError)
    156. {
    157. isConnected = true;
    158. }
    159. }
    160. if (NULL != Overlapped.hEvent)
    161. {
    162. ::CloseHandle(Overlapped.hEvent);
    163. }
    164. m_bConnected = isConnected;
    165. return isConnected;
    166. }
    167. bool CNamedPipe::Disconnect()
    168. {
    169. if (INVALID_HANDLE_VALUE == m_hNamedPipe)
    170. {
    171. return false;
    172. }
    173. //参数句柄必须由 CreateNamedPipe 函数创建
    174. return ::DisconnectNamedPipe(m_hNamedPipe);
    175. }
    176. void CNamedPipe::Close()
    177. {
    178. if (INVALID_HANDLE_VALUE != m_hNamedPipe)
    179. {
    180. if (m_bConnected)
    181. {
    182. ::FlushFileBuffers(m_hNamedPipe);
    183. ::DisconnectNamedPipe(m_hNamedPipe);
    184. m_bConnected = false;
    185. }
    186. ::CloseHandle(m_hNamedPipe);
    187. m_hNamedPipe = INVALID_HANDLE_VALUE;
    188. }
    189. }
    190. bool CNamedPipe::IsValid()
    191. {
    192. return INVALID_HANDLE_VALUE != m_hNamedPipe;
    193. }
    194. bool CNamedPipe::Read(LPVOID lpData, DWORD nSize, LPDWORD lpBytesRead/* = nullptr*/, DWORD nTimeOut)
    195. {
    196. OVERLAPPED Overlapped = { 0 };
    197. Overlapped.hEvent = m_hReadEvent;
    198. DWORD dwBytesTransferred = 0;
    199. bool isSuccess = false;
    200. if (nullptr == m_pBuffer ||
    201. nullptr == lpData ||
    202. 0 == nSize ||
    203. nSize > PIPE_BUF_MAX_SIZE
    204. )
    205. {
    206. return false;
    207. }
    208. PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;
    209. if (!::ReadFile(m_hNamedPipe, &pData->dwSize, sizeof(PIPE_DATA), NULL, &Overlapped))
    210. {
    211. //管道已结束
    212. if (ERROR_BROKEN_PIPE == ::GetLastError())
    213. {
    214. return false;
    215. }
    216. if (ERROR_IO_PENDING != ::GetLastError())
    217. {
    218. return false;
    219. }
    220. if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
    221. {
    222. return false;
    223. }
    224. }
    225. if (pData->dwSize > PIPE_BUF_MAX_SIZE)
    226. {
    227. return false;
    228. }
    229. if (!::ReadFile(m_hNamedPipe, pData->data, pData->dwSize, NULL, &Overlapped))
    230. {
    231. if (ERROR_IO_PENDING != ::GetLastError())
    232. {
    233. return false;
    234. }
    235. if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
    236. {
    237. return false;
    238. }
    239. }
    240. if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true))
    241. {
    242. isSuccess = true;
    243. if (lpBytesRead)
    244. {
    245. *lpBytesRead = dwBytesTransferred;
    246. }
    247. }
    248. if (isSuccess)
    249. {
    250. if (nSize < pData->dwSize)
    251. {
    252. ::memcpy_s(lpData, nSize, pData->data, nSize);
    253. }
    254. else
    255. {
    256. ::memcpy_s(lpData, nSize, pData->data, pData->dwSize);
    257. }
    258. }
    259. return isSuccess;
    260. }
    261. bool CNamedPipe::Write(LPCVOID lpData, DWORD nSize, LPDWORD lpBytesWritten/* = nullptr*/, DWORD nTimeOut)
    262. {
    263. OVERLAPPED Overlapped = { 0 };
    264. Overlapped.hEvent = m_hWriteEvent;
    265. DWORD dwBytesTransferred = 0;
    266. bool isSuccess = false;
    267. if (nullptr == m_pBuffer ||
    268. nullptr == lpData ||
    269. 0 == nSize ||
    270. nSize > PIPE_BUF_MAX_SIZE
    271. )
    272. {
    273. return false;
    274. }
    275. PPIPE_DATA pData = (PPIPE_DATA)m_pBuffer;
    276. DWORD dwBytesToWrite = nSize + sizeof(PIPE_DATA);
    277. pData->dwSize = nSize;
    278. ::memcpy_s(pData->data, PIPE_BUF_MAX_SIZE, lpData, nSize);
    279. if (::WriteFile(m_hNamedPipe, pData, dwBytesToWrite, NULL, &Overlapped))
    280. {
    281. return true;
    282. }
    283. //管道正在被关闭
    284. if (ERROR_NO_DATA == ::GetLastError())
    285. {
    286. return false;
    287. }
    288. //管道已结束
    289. if (ERROR_BROKEN_PIPE == ::GetLastError())
    290. {
    291. return false;
    292. }
    293. //重叠
    294. if (ERROR_IO_PENDING != ::GetLastError())
    295. {
    296. return false;
    297. }
    298. if (WAIT_OBJECT_0 != ::WaitForSingleObject(Overlapped.hEvent, nTimeOut))
    299. {
    300. return false;
    301. }
    302. if (::GetOverlappedResult(m_hNamedPipe, &Overlapped, &dwBytesTransferred, true))
    303. {
    304. isSuccess = true;
    305. if (lpBytesWritten)
    306. {
    307. *lpBytesWritten = dwBytesTransferred;
    308. }
    309. }
    310. return isSuccess;
    311. }
    312. bool CNamedPipe::Initialize()
    313. {
    314. bool isSuccess = false;
    315. if (m_bInit)
    316. {
    317. return true;
    318. }
    319. do
    320. {
    321. if (nullptr == m_pBuffer)
    322. {
    323. m_pBuffer = ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, PIPE_BUF_MAX_SIZE + sizeof(PIPE_DATA));
    324. }
    325. if (nullptr == m_pBuffer)
    326. {
    327. break;
    328. }
    329. if (NULL == m_hReadEvent)
    330. {
    331. m_hReadEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    332. }
    333. if (NULL == m_hReadEvent)
    334. {
    335. break;
    336. }
    337. if (NULL == m_hWriteEvent)
    338. {
    339. m_hWriteEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    340. }
    341. if (NULL == m_hWriteEvent)
    342. {
    343. break;
    344. }
    345. isSuccess = true;
    346. } while (false);
    347. if (!isSuccess)
    348. {
    349. Uninitialize();
    350. }
    351. m_bInit = isSuccess;
    352. return m_bInit;
    353. }
    354. void CNamedPipe::Uninitialize()
    355. {
    356. if (!m_bInit)
    357. {
    358. return;
    359. }
    360. //关闭管道
    361. this->Close();
    362. //释放读写缓冲
    363. if (nullptr != m_pBuffer)
    364. {
    365. ::HeapFree(::GetProcessHeap(), 0, m_pBuffer);
    366. m_pBuffer = nullptr;
    367. }
    368. //关闭事件
    369. if (m_hReadEvent)
    370. {
    371. CloseHandle(m_hReadEvent);
    372. m_hReadEvent = NULL;
    373. }
    374. if (m_hWriteEvent)
    375. {
    376. CloseHandle(m_hWriteEvent);
    377. m_hWriteEvent = NULL;
    378. }
    379. m_bInit = false;
    380. }

    main.cpp

    1. #include
    2. #include "Utils/CNamedPipe.h"
    3. #include
    4. #include
    5. int main()
    6. {
    7. std::promise<bool> p;
    8. std::future<bool> f = p.get_future();
    9. std::thread(
    10. [&p]()
    11. {
    12. static char szBuf[1024 * 64] = { 0 };
    13. CNamedPipe pipe;
    14. if (!pipe.Create(_T("FlameCyclone")))
    15. {
    16. std::cout << "Create failed!" << std::endl;
    17. p.set_value(false);
    18. return;
    19. }
    20. p.set_value(true);
    21. while (true)
    22. {
    23. if (!pipe.WaitConnect())
    24. {
    25. std::cout << "WaitConnect failed!" << std::endl;
    26. break;
    27. }
    28. while (true)
    29. {
    30. bool isSuccess = pipe.Read(szBuf, sizeof(szBuf));
    31. if (isSuccess)
    32. {
    33. std::cout << "recv: " << szBuf << std::endl;
    34. }
    35. //另一端断开则重新等待连接
    36. if (ERROR_BROKEN_PIPE == ::GetLastError())
    37. {
    38. pipe.Disconnect();
    39. if (!pipe.WaitConnect())
    40. {
    41. std::cout << "WaitConnect failed!" << std::endl;
    42. return;
    43. }
    44. }
    45. }
    46. }
    47. }
    48. ).detach();
    49. if (!f.get())
    50. {
    51. return -1;
    52. }
    53. CNamedPipe pipe;
    54. if (!pipe.Open(_T("FlameCyclone"), 5000))
    55. {
    56. std::cout << "Open failed!" << std::endl;
    57. return -1;
    58. }
    59. std::string strMsg;
    60. while (true)
    61. {
    62. std::cin >> strMsg;
    63. std::cout << "send: " << strMsg << std::endl;
    64. if (!pipe.Write(strMsg.c_str(), strMsg.size() + 1))
    65. {
    66. std::cout << "Write failed!" << std::endl;
    67. break;
    68. }
    69. }
    70. system("pause");
    71. return 0;
    72. }

     

     

  • 相关阅读:
    幻读是什么,幻读有什么问题
    Microservices communication
    C语言程序编译过程中自动添加编译时间等相关信息
    AUTOSAR实战篇:基于ETAS工具链的信息安全协议栈集成指南
    使用kubenetes dashboard控制台部署项目
    MyBatis学习之SQL查询参数以及增删改操作
    ORA-22992 cannot use LOB locators selected from remote tables
    MyBatis中只有一个参数时--如何判断null呢?
    js(javascript)中页面跳转和窗口关闭等操作
    Qt之读写文件
  • 原文地址:https://blog.csdn.net/Flame_Cyclone/article/details/133987446