SocketClientImpl.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #ifndef __SOCKETCLIENTIMPL_20160228__
  2. #define __SOCKETCLIENTIMPL_20160228__
  3. #pragma once
  4. #pragma warning(push)
  5. #pragma warning(disable:4995)
  6. #include <vector>
  7. #pragma warning(pop)
  8. #include "SocketHandle.h"
  9. /************************************************************************/
  10. /* Copyright (C), 2016-2020, [IT], 保留所有权利;
  11. /* 模 块 名:ISocketClientHandler;
  12. /* 描 述:Event handler that SocketClientImpl<T> must implement;
  13. * This class is not required, you can do the same thing as long your class exposes these functions.
  14. * (These are not pure to save you some typing);
  15. /*
  16. /* 版 本:[V];
  17. /* 作 者:[IT];
  18. /* 日 期:[2/23/2016];
  19. /*
  20. /*
  21. /* 注 意:;
  22. /*
  23. /* 修改记录:[IT];
  24. /* 修改日期:;
  25. /* 修改版本:;
  26. /* 修改内容:;
  27. /************************************************************************/
  28. class ISocketClientHandler
  29. {
  30. public:
  31. virtual void OnThreadBegin(CSocketHandle* ) {}
  32. virtual void OnThreadExit(CSocketHandle* ) {}
  33. virtual void OnDataReceived(CSocketHandle* , const BYTE* , DWORD , const SockAddrIn& ) {}
  34. virtual void OnConnectionDropped(CSocketHandle* ) {}
  35. virtual void OnConnectionError(CSocketHandle* , DWORD ) {}
  36. };
  37. /************************************************************************/
  38. /* Copyright (C), 2016-2020, [IT], 保留所有权利;
  39. /* 模 块 名:SocketClientImpl<T, tBufferSize>;
  40. /* 描 述:Because <typename T> may refer to any class of your choosing,Client Communication wrapper;
  41. /*
  42. /* 版 本:[V];
  43. /* 作 者:[IT];
  44. /* 日 期:[2/23/2016];
  45. /*
  46. /*
  47. /* 注 意:;
  48. /*
  49. /* 修改记录:[IT];
  50. /* 修改日期:;
  51. /* 修改版本:;
  52. /* 修改内容:;
  53. /************************************************************************/
  54. template <typename T, size_t tBufferSize = 2048>
  55. class SocketClientImpl
  56. {
  57. typedef SocketClientImpl<T, tBufferSize> thisClass;
  58. public:
  59. SocketClientImpl(): _pInterface(0), _thread(0)
  60. {
  61. }
  62. void SetInterface(T* pInterface)
  63. {
  64. ::InterlockedExchangePointer(reinterpret_cast<void**>(&_pInterface), pInterface);
  65. }
  66. operator CSocketHandle*() throw()
  67. {
  68. return( &_socket );
  69. }
  70. CSocketHandle* operator->() throw()
  71. {
  72. return( &_socket );
  73. }
  74. bool IsOpen() const
  75. {
  76. return _socket.IsOpen();
  77. }
  78. bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  79. {
  80. return _socket.CreateSocket(pszHost, pszServiceName, nFamily, nType, uOptions);
  81. }
  82. bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType)
  83. {
  84. return _socket.ConnectTo(pszHostName, pszRemote, pszServiceName, nFamily, nType);
  85. }
  86. void Close()
  87. {
  88. _socket.Close();
  89. }
  90. DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  91. {
  92. return _socket.Read(lpBuffer, dwSize, lpAddrIn, dwTimeout);
  93. }
  94. DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  95. {
  96. return _socket.Write(lpBuffer, dwCount, lpAddrIn, dwTimeout);
  97. }
  98. bool StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
  99. void Terminate(DWORD dwTimeout = INFINITE);
  100. static bool IsConnectionDropped(DWORD dwError);
  101. protected:
  102. void Run();
  103. static DWORD WINAPI SocketClientProc(thisClass* _this);
  104. T* _pInterface;
  105. HANDLE _thread;
  106. CSocketHandle _socket;
  107. };
  108. template <typename T, size_t tBufferSize>
  109. bool SocketClientImpl<T, tBufferSize>::StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  110. {
  111. // must be closed first...
  112. if ( IsOpen() ) return false;
  113. bool result = false;
  114. if ( nType == SOCK_STREAM )
  115. {
  116. result = _socket.ConnectTo(pszHost, pszRemote, pszServiceName, nFamily, nType); // TCP
  117. }
  118. else
  119. {
  120. // let provider select a port for us
  121. result = _socket.CreateSocket(pszHost, TEXT("0"), nFamily, nType, uOptions); // UDP
  122. }
  123. if ( result )
  124. {
  125. _thread = AtlCreateThread(SocketClientProc, this);
  126. if ( _thread == NULL )
  127. {
  128. DWORD dwError = GetLastError();
  129. _socket.Close();
  130. SetLastError(dwError);
  131. result = false;
  132. }
  133. }
  134. return result;
  135. }
  136. template <typename T, size_t tBufferSize>
  137. void SocketClientImpl<T, tBufferSize>::Run()
  138. {
  139. SockAddrIn addrIn;
  140. std::vector<unsigned char> data;
  141. data.resize( tBufferSize );
  142. DWORD dwRead;
  143. DWORD dwError;
  144. _ASSERTE( _pInterface != NULL && "Need an interface to pass events");
  145. // Notification: OnThreadBegin
  146. if ( _pInterface != NULL ) {
  147. _pInterface->OnThreadBegin(*this);
  148. }
  149. int type = _socket.GetSocketType();
  150. if (type == SOCK_STREAM) {
  151. _socket.GetPeerName( addrIn );
  152. }
  153. while ( _socket.IsOpen() )
  154. {
  155. if (type == SOCK_STREAM)
  156. {
  157. dwRead = _socket.Read(&data[0], tBufferSize, NULL, INFINITE);
  158. }
  159. else
  160. {
  161. dwRead = _socket.Read(&data[0], tBufferSize, addrIn, INFINITE);
  162. }
  163. if ( (dwRead != -1L) && (dwRead > 0))
  164. {
  165. // Notification: OnDataReceived
  166. if ( _pInterface != NULL ) {
  167. _pInterface->OnDataReceived(*this, &data[0], dwRead, addrIn);
  168. }
  169. }
  170. else if (type == SOCK_STREAM && dwRead == 0L )
  171. {
  172. // connection broken
  173. if ( _pInterface != NULL )
  174. {
  175. _pInterface->OnConnectionDropped(*this);
  176. }
  177. break;
  178. }
  179. else if ( dwRead == -1L )
  180. {
  181. dwError = GetLastError();
  182. if ( _pInterface != NULL )
  183. {
  184. if (IsConnectionDropped( dwError) ) {
  185. // Notification: OnConnectionDropped
  186. if (type == SOCK_STREAM || (dwError == WSAENOTSOCK || dwError == WSAENETDOWN))
  187. {
  188. _pInterface->OnConnectionDropped(*this);
  189. break;
  190. }
  191. }
  192. // Notification: OnConnectionError
  193. _pInterface->OnConnectionError(*this, dwError);
  194. }
  195. else {
  196. break;
  197. }
  198. }
  199. }
  200. data.clear();
  201. // Notification: OnThreadExit
  202. if ( _pInterface != NULL ) {
  203. _pInterface->OnThreadExit(*this);
  204. }
  205. }
  206. template <typename T, size_t tBufferSize>
  207. void SocketClientImpl<T, tBufferSize>::Terminate(DWORD dwTimeout /*= INFINITE*/)
  208. {
  209. _socket.Close();
  210. if ( _thread != NULL )
  211. {
  212. if ( WaitForSingleObject(_thread, dwTimeout) == WAIT_TIMEOUT ) {
  213. TerminateThread(_thread, 1);
  214. }
  215. CloseHandle(_thread);
  216. _thread = NULL;
  217. }
  218. }
  219. template <typename T, size_t tBufferSize>
  220. DWORD WINAPI SocketClientImpl<T, tBufferSize>::SocketClientProc(thisClass* _this)
  221. {
  222. if ( _this != NULL )
  223. {
  224. _this->Run();
  225. }
  226. return 0;
  227. }
  228. template <typename T, size_t tBufferSize>
  229. bool SocketClientImpl<T, tBufferSize>::IsConnectionDropped(DWORD dwError)
  230. {
  231. // see: winerror.h for definition
  232. switch( dwError )
  233. {
  234. case WSAENOTSOCK:
  235. case WSAENETDOWN:
  236. case WSAENETUNREACH:
  237. case WSAENETRESET:
  238. case WSAECONNABORTED:
  239. case WSAECONNRESET:
  240. case WSAESHUTDOWN:
  241. case WSAEHOSTDOWN:
  242. case WSAEHOSTUNREACH:
  243. return true;
  244. default:
  245. break;
  246. }
  247. return false;
  248. }
  249. #endif // __SOCKETCLIENTIMPL_20160228__