PipeService.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #pragma once
  2. #include "Protocol.h"
  3. #define CONNECTING_STATE 0
  4. #define READING_STATE 1
  5. #define WRITING_STATE 2
  6. #define INSTANCES 4
  7. #define PIPE_TIMEOUT 5000
  8. #define BUFSIZE 4096
  9. // 命名管道在完成端口上投递的I/O操作的类型
  10. typedef enum _OPERATION_TYPE
  11. {
  12. OP_ACCEPT, // Accept操作;
  13. OP_SEND, // 发送操作
  14. OP_RECV, // 接收操作
  15. OP_MAX // 上限;
  16. } OPERATION_TYPE;
  17. extern void dprintf(TCHAR* pszStr, ...);
  18. // 单个IO请求;
  19. typedef struct _PER_IO_CONTEXT
  20. {
  21. OVERLAPPED m_Overlapped;
  22. HANDLE m_PipeAccept;
  23. OPERATION_TYPE m_OpType;
  24. // 接收客户端的消息;
  25. BYTE szBuffer[BUFSIZE];
  26. DWORD dwBufferLine;
  27. // 发送给客户的消息;
  28. //TCHAR chReply[BUFSIZE];
  29. //DWORD cbToWrite;
  30. // 管道状态;
  31. //DWORD dwState;
  32. // IO是否在等待;
  33. //BOOL fPendingIO;
  34. // 创建写IO;
  35. _PER_IO_CONTEXT *pWriteIoContext;
  36. // 初始化
  37. _PER_IO_CONTEXT()
  38. {
  39. ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  40. ZeroMemory(szBuffer, BUFSIZE);
  41. //ZeroMemory(chReply, BUFSIZE);
  42. m_PipeAccept = INVALID_HANDLE_VALUE;
  43. m_OpType = OP_ACCEPT;
  44. pWriteIoContext = NULL;
  45. //fPendingIO = FALSE;
  46. //dwState = 0;
  47. }
  48. // 释放掉句柄
  49. ~_PER_IO_CONTEXT()
  50. {
  51. if (m_PipeAccept != INVALID_HANDLE_VALUE)
  52. {
  53. //CloseHandle(m_PipeAccept);// 此处不能CloseHandle,因为m_PipeAccept在PER_PIPE_CONTEXT中已释放;
  54. m_PipeAccept = INVALID_HANDLE_VALUE;
  55. }
  56. if ( pWriteIoContext )
  57. delete pWriteIoContext;
  58. pWriteIoContext = NULL;
  59. }
  60. // 重置缓冲区内容
  61. void ResetBuffer()
  62. {
  63. dprintf(_T("ResetBuffer:%p"), &m_Overlapped);
  64. ZeroMemory(szBuffer, BUFSIZE);
  65. //ZeroMemory(chReply, BUFSIZE);
  66. }
  67. } PER_IO_CONTEXT, *PPER_IO_CONTEXT;
  68. typedef struct _PER_PIPE_CONTEXT
  69. {
  70. HANDLE m_hPipe;
  71. // 客户端进程PID;
  72. DWORD dwProcessId;
  73. // 客户端进程窗口名称;
  74. TCHAR szClientName[255];
  75. // 该Pipe下的所有IO事件;
  76. CArray<_PER_IO_CONTEXT*> m_arrayIoContext;
  77. _PER_PIPE_CONTEXT()
  78. {
  79. m_hPipe = INVALID_HANDLE_VALUE;
  80. dwProcessId = 0;
  81. memset(szClientName, 0, sizeof(TCHAR)*255);
  82. }
  83. ~_PER_PIPE_CONTEXT()
  84. {
  85. if ( m_hPipe != INVALID_HANDLE_VALUE )
  86. {
  87. CloseHandle(m_hPipe);
  88. m_hPipe = INVALID_HANDLE_VALUE;
  89. // 释放掉所有的IO上下文数据
  90. for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
  91. {
  92. delete m_arrayIoContext.GetAt(i);
  93. }
  94. m_arrayIoContext.RemoveAll();
  95. }
  96. }
  97. // 设置客户端信息;
  98. void SetClientInfo(DWORD dwClientId, LPCTSTR lpszClientName)
  99. {
  100. dwProcessId = dwClientId;
  101. _stprintf_s(szClientName, _T("%s"), lpszClientName == NULL ? _T("Null") : lpszClientName);
  102. }
  103. // 获取一个新的IoContext
  104. _PER_IO_CONTEXT* GetNewIoContext()
  105. {
  106. _PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
  107. m_arrayIoContext.Add( p );
  108. return p;
  109. }
  110. // 从数组中移除一个指定的IoContext
  111. void RemoveContext( _PER_IO_CONTEXT* pContext )
  112. {
  113. ASSERT( pContext!=NULL );
  114. for( int i=0; i<m_arrayIoContext.GetCount(); i++ )
  115. {
  116. if( pContext == m_arrayIoContext.GetAt(i) )
  117. {
  118. if ( pContext->pWriteIoContext )
  119. delete pContext->pWriteIoContext;
  120. delete pContext;
  121. pContext = NULL;
  122. m_arrayIoContext.RemoveAt(i);
  123. break;
  124. }
  125. }
  126. }
  127. }PER_PIPE_CONTEXT, *PPER_PIPE_CONTEXT;
  128. // 回调客户端接入时;
  129. typedef BOOL(CALLBACK *OnGoCallback)(DATAHEADER *pHeader, MSG_INFO* pMsg);
  130. // 回调客户端接入时;
  131. typedef BOOL(CALLBACK *OnConnectCallback)(DATAHEADER *pHeader, MSG_INFO* pMsg);
  132. // 回调客户端断开时;
  133. typedef BOOL(CALLBACK* OnDisconnectCallback)(PER_IO_CONTEXT* pIoContext);
  134. // 回调客户端消息到来时;
  135. typedef BOOL(CALLBACK *OnReciveCallback)(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
  136. // 工作者线程的线程参数
  137. class CIOCPPipe;
  138. typedef struct _tagThreadParams_WORKER
  139. {
  140. CIOCPPipe *pIOCPModel; // 类指针,用于调用类中的函数
  141. int nThreadNo; // 线程编号
  142. } THREADPARAMS_WORKER, *PTHREADPARAM_WORKER;
  143. // CIOCPPipe类
  144. class CIOCPPipe
  145. {
  146. public:
  147. CIOCPPipe(void);
  148. ~CIOCPPipe(void);
  149. public:
  150. // 启动服务器
  151. bool Start();
  152. // 停止服务器
  153. void Stop();
  154. // 设置主界面的指针,用于调用显示信息到界面中
  155. void SetMainDlg(CDialog *p) { m_pMain = p; }
  156. // 向客户端发送消息;
  157. BOOL SendPackage(DATAHEADER &header, MSG_INFO &msg);
  158. // SetCallback;
  159. static void SetCallBack(LPVOID lpOnConnect, LPVOID lpOnDisconnect, LPVOID lpOnGo, LPVOID lpOnRecive)
  160. {
  161. if ( lpOnConnectCallback == NULL )
  162. lpOnConnectCallback = (OnConnectCallback)lpOnConnect;
  163. if ( lpOnDisconnectCallback == NULL )
  164. lpOnDisconnectCallback = (OnDisconnectCallback)lpOnDisconnect;
  165. if ( lpOnGoCallback == NULL )
  166. lpOnGoCallback = (OnGoCallback)lpOnGo;
  167. if ( lpOnReciveCallback == NULL )
  168. lpOnReciveCallback = (OnReciveCallback)lpOnRecive;
  169. }
  170. protected:
  171. // 初始化IOCP
  172. bool InitIOCP();
  173. // 最后释放资源
  174. void DeInitialize();
  175. // 投递Accept请求
  176. bool PostAccept();
  177. // 投递接收数据请求
  178. bool PostRecv(PER_IO_CONTEXT *pIoContext);
  179. // 在有客户端连入的时候,进行处理
  180. bool DoAccpet(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
  181. // 在有接收的数据到达的时候,进行处理
  182. bool DoRecv(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
  183. // 将客户端的相关信息存储到数组中
  184. void AddToContextList(PER_PIPE_CONTEXT *pPipeContext);
  185. // 将客户端的信息从数组中移除
  186. void RemoveContext(PER_PIPE_CONTEXT *pPipeContext);
  187. // 清空客户端信息
  188. void ClearContextList();
  189. // 将句柄绑定到完成端口中
  190. bool AssociateWithIOCP(PER_IO_CONTEXT *pIoContext);
  191. // 处理完成端口上的错误
  192. bool HandleError(PER_PIPE_CONTEXT *pPipeContext, const DWORD &dwErr);
  193. // 线程函数,为IOCP请求服务的工作者线程
  194. static DWORD WINAPI _WorkerThread(LPVOID lpParam);
  195. // 获得本机的处理器数量
  196. int GetNoOfProcessors();
  197. // 判断客户端Socket是否已经断开
  198. bool IsSocketAlive(SOCKET s);
  199. // 在主界面中显示信息
  200. void ShowMessage(const CString szFormat, ...) const;
  201. // 处理返回值;
  202. void RecvProcess(PER_PIPE_CONTEXT* pPipeContext, PER_IO_CONTEXT* pIoContext);
  203. private:
  204. static OnConnectCallback lpOnConnectCallback;
  205. static OnDisconnectCallback lpOnDisconnectCallback;
  206. static OnGoCallback lpOnGoCallback;
  207. static OnReciveCallback lpOnReciveCallback;
  208. HANDLE m_hShutdownEvent; // 用来通知线程系统退出的事件,为了能够更好的退出线程
  209. HANDLE m_hIOCompletionPort; // 完成端口的句柄
  210. HANDLE *m_phWorkerThreads; // 工作者线程的句柄指针
  211. int m_nThreads; // 生成的线程数量
  212. CDialog *m_pMain; // 主界面的界面指针,用于在主界面中显示消息
  213. CRITICAL_SECTION m_csContextList; // 用于Worker线程同步的互斥量
  214. CArray<PER_PIPE_CONTEXT *> m_arrayClientContext; // 客户端Socket的Context信息
  215. };