SATTCPServer.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #pragma once
  2. // winsock 2 的头文件和库
  3. #include <winsock2.h>
  4. #include <MSWSock.h>
  5. //#include <ws2tcpip.h>
  6. #pragma comment(lib,"ws2_32.lib")
  7. #include "SATProtocol.h"
  8. // 缓冲区长度 (1024*8)
  9. // 之所以为什么设置8K,也是一个江湖上的经验值
  10. // 如果确实客户端发来的每组数据都比较少,那么就设置得小一些,省内存
  11. #define MAX_BUFFER_LEN 8192
  12. // 默认端口
  13. #define DEFAULT_PORT 5588
  14. // 默认IP地址
  15. #define DEFAULT_IP _T("127.0.0.1")
  16. //////////////////////////////////////////////////////////////////
  17. // 在完成端口上投递的I/O操作的类型
  18. typedef enum _OPERATION_TYPE
  19. {
  20. ACCEPT_POSTED, // 标志投递的Accept操作
  21. SEND_POSTED, // 标志投递的是发送操作
  22. RECV_POSTED, // 标志投递的是接收操作
  23. NULL_POSTED // 用于初始化,无意义
  24. }OPERATION_TYPE;
  25. //====================================================================================
  26. //
  27. // 单IO数据结构体定义(用于每一个重叠操作的参数)
  28. //
  29. //====================================================================================
  30. typedef struct _PER_IO_CONTEXT
  31. {
  32. OVERLAPPED m_Overlapped; // 每一个重叠网络操作的重叠结构(针对每一个Socket的每一个操作,都要有一个)
  33. SOCKET m_sockAccept; // 这个网络操作所使用的Socket
  34. WSABUF m_wsaBuf; // WSA类型的缓冲区,用于给重叠操作传参数的
  35. char m_szBuffer[MAX_BUFFER_LEN]; // 这个是WSABUF里具体存字符的缓冲区
  36. OPERATION_TYPE m_OpType; // 标识网络操作的类型(对应上面的枚举)
  37. // 初始化
  38. _PER_IO_CONTEXT()
  39. {
  40. ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  41. ZeroMemory( m_szBuffer,MAX_BUFFER_LEN );
  42. m_sockAccept = INVALID_SOCKET;
  43. m_wsaBuf.buf = m_szBuffer;
  44. m_wsaBuf.len = MAX_BUFFER_LEN;
  45. m_OpType = NULL_POSTED;
  46. }
  47. // 释放掉Socket
  48. ~_PER_IO_CONTEXT()
  49. {
  50. if( m_sockAccept!=INVALID_SOCKET )
  51. {
  52. int nRet = shutdown(m_sockAccept, SD_BOTH);
  53. if ( nRet != 0 )
  54. OutputDebugString(_T("================>shutdown m_sockAccept套接字出错。<================\n"));
  55. else
  56. OutputDebugString(_T("================>shutdown m_sockAccept套接字成功。<================\n"));
  57. nRet = closesocket(m_sockAccept);
  58. if ( nRet != 0 )
  59. OutputDebugString(_T("================>closesocket m_sockAccept套接字出错。<================\n"));
  60. else
  61. OutputDebugString(_T("================>closesocket m_sockAccept套接字成功。<================\n"));
  62. m_sockAccept = INVALID_SOCKET;
  63. OutputDebugString(_T("================>释放m_sockAccept套接字<================\n"));
  64. }
  65. }
  66. // 重置缓冲区内容
  67. void ResetBuffer()
  68. {
  69. ZeroMemory( m_szBuffer,MAX_BUFFER_LEN );
  70. }
  71. } PER_IO_CONTEXT, *PPER_IO_CONTEXT;
  72. //====================================================================================
  73. //
  74. // 单句柄数据结构体定义(用于每一个完成端口,也就是每一个Socket的参数)
  75. //
  76. //====================================================================================
  77. typedef struct _PER_SOCKET_CONTEXT
  78. {
  79. SOCKET m_Socket; // 每一个客户端连接的Socket
  80. SOCKADDR_IN m_ClientAddr; // 客户端的地址
  81. CArray<_PER_IO_CONTEXT*> m_arrayIoContext; // 客户端网络操作的上下文数据,
  82. // 也就是说对于每一个客户端Socket,是可以在上面同时投递多个IO请求的
  83. std::string lastData;
  84. // 初始化
  85. _PER_SOCKET_CONTEXT()
  86. {
  87. m_Socket = INVALID_SOCKET;
  88. memset(&m_ClientAddr, 0, sizeof(m_ClientAddr));
  89. }
  90. // 释放资源
  91. ~_PER_SOCKET_CONTEXT()
  92. {
  93. if( m_Socket!=INVALID_SOCKET )
  94. {
  95. int nRet = shutdown(m_Socket, SD_BOTH);
  96. if ( nRet != 0 )
  97. OutputDebugString(_T("================>shutdown m_Socket套接字出错。<================\n"));
  98. else
  99. OutputDebugString(_T("================>shutdown m_Socket套接字成功。<================\n"));
  100. nRet = closesocket(m_Socket);
  101. if ( nRet != 0 )
  102. OutputDebugString(_T("================>closesocket m_Socket套接字出错。<================\n"));
  103. else
  104. OutputDebugString(_T("================>closesocket m_Socket套接字成功。<================\n"));
  105. m_Socket = INVALID_SOCKET;
  106. }
  107. // 释放掉所有的IO上下文数据
  108. for( int i=0;i<m_arrayIoContext.GetCount();i++ )
  109. {
  110. delete m_arrayIoContext.GetAt(i);
  111. }
  112. m_arrayIoContext.RemoveAll();
  113. }
  114. // 获取一个新的IoContext
  115. _PER_IO_CONTEXT* GetNewIoContext()
  116. {
  117. _PER_IO_CONTEXT* p = new _PER_IO_CONTEXT;
  118. m_arrayIoContext.Add( p );
  119. return p;
  120. }
  121. // 从数组中移除一个指定的IoContext
  122. void RemoveContext( _PER_IO_CONTEXT* pContext )
  123. {
  124. ASSERT( pContext!=NULL );
  125. for( int i=0;i<m_arrayIoContext.GetCount();i++ )
  126. {
  127. if( pContext==m_arrayIoContext.GetAt(i) )
  128. {
  129. delete pContext;
  130. pContext = NULL;
  131. m_arrayIoContext.RemoveAt(i);
  132. break;
  133. }
  134. }
  135. }
  136. } PER_SOCKET_CONTEXT, *PPER_SOCKET_CONTEXT;
  137. //====================================================================================
  138. //
  139. // CSATTCPServer类定义
  140. //
  141. //====================================================================================
  142. // 工作者线程的线程参数
  143. class CSATTCPServer;
  144. typedef struct _tagThreadParams_WORKER
  145. {
  146. CSATTCPServer* pIOCPModel; // 类指针,用于调用类中的函数
  147. int nThreadNo; // 线程编号
  148. } THREADPARAMS_WORKER,*PTHREADPARAM_WORKER;
  149. // CSATTCPServer类
  150. class CSATTCPServer
  151. {
  152. CSATTCPServer(void);
  153. public:
  154. ~CSATTCPServer(void);
  155. // 单例对象模式;
  156. static CSATTCPServer* GetInstance()
  157. {
  158. static CSATTCPServer* pInstance = NULL;
  159. if ( pInstance == NULL )
  160. {
  161. pInstance = new CSATTCPServer;
  162. }
  163. return pInstance;
  164. }
  165. public:
  166. // 启动服务器
  167. bool Start(unsigned int port);
  168. // 停止服务器
  169. void Stop();
  170. // 加载Socket库
  171. bool LoadSocketLib();
  172. // 卸载Socket库,彻底完事
  173. void UnloadSocketLib() { WSACleanup(); }
  174. // 获得本机的IP地址
  175. CString GetLocalIP();
  176. // 设置监听端口
  177. void SetPort( const int& nPort ) { m_nPort=nPort; }
  178. // 设置主界面的指针,用于调用显示信息到界面中
  179. void SetMainDlg( CDialog* p ) { m_pMain=p; }
  180. protected:
  181. // 初始化IOCP
  182. bool _InitializeIOCP();
  183. // 初始化Socket
  184. bool _InitializeListenSocket(unsigned int port);
  185. // 最后释放资源
  186. void _DeInitialize();
  187. // 投递Accept请求
  188. bool _PostAccept( PER_IO_CONTEXT* pAcceptIoContext );
  189. // 投递接收数据请求
  190. bool _PostRecv( PER_IO_CONTEXT* pIoContext );
  191. // 在有客户端连入的时候,进行处理
  192. bool _DoAccpet( PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext );
  193. // 在有接收的数据到达的时候,进行处理
  194. bool _DoRecv( PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext );
  195. // 将客户端的相关信息存储到数组中
  196. void _AddToContextList( PER_SOCKET_CONTEXT *pSocketContext );
  197. // 将客户端的信息从数组中移除
  198. void _RemoveContext( PER_SOCKET_CONTEXT *pSocketContext );
  199. // 清空客户端信息
  200. void _ClearContextList();
  201. // 将句柄绑定到完成端口中
  202. bool _AssociateWithIOCP( PER_SOCKET_CONTEXT *pContext);
  203. // 处理完成端口上的错误
  204. bool HandleError( PER_SOCKET_CONTEXT *pContext,const DWORD& dwErr );
  205. // 线程函数,为IOCP请求服务的工作者线程
  206. static DWORD WINAPI _WorkerThread(LPVOID lpParam);
  207. // 获得本机的处理器数量
  208. int _GetNoOfProcessors();
  209. // 判断客户端Socket是否已经断开
  210. bool _IsSocketAlive(SOCKET s);
  211. // 在主界面中显示信息
  212. void _ShowMessage( const CString szFormat,...) const;
  213. void _RecvProcess(PER_SOCKET_CONTEXT* pSocketContext, PER_IO_CONTEXT* pIoContext);
  214. void _TaskProcess(PER_IO_CONTEXT* pIoContext, SATPROTO::Package *pak);
  215. bool CheckDataHeader(SATPROTO::DataHeader* header);
  216. private:
  217. HANDLE m_hShutdownEvent; // 用来通知线程系统退出的事件,为了能够更好的退出线程
  218. HANDLE m_hIOCompletionPort; // 完成端口的句柄
  219. HANDLE* m_phWorkerThreads; // 工作者线程的句柄指针
  220. int m_nThreads; // 生成的线程数量
  221. CString m_strIP; // 服务器端的IP地址
  222. int m_nPort; // 服务器端的监听端口
  223. CDialog* m_pMain; // 主界面的界面指针,用于在主界面中显示消息
  224. CRITICAL_SECTION m_csContextList; // 用于Worker线程同步的互斥量
  225. CArray<PER_SOCKET_CONTEXT*> m_arrayClientContext; // 客户端Socket的Context信息
  226. PER_SOCKET_CONTEXT* m_pListenContext; // 用于监听的Socket的Context信息
  227. LPFN_ACCEPTEX m_lpfnAcceptEx; // AcceptEx 和 GetAcceptExSockaddrs 的函数指针,用于调用这两个扩展函数
  228. LPFN_GETACCEPTEXSOCKADDRS m_lpfnGetAcceptExSockAddrs;
  229. };