SocketClientImpl.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 = 1024*64>
  55. class SocketClientImpl
  56. {
  57. typedef SocketClientImpl<T, tBufferSize> thisClass;
  58. public:
  59. SocketClientImpl(): _pInterface(0), _thread(0)
  60. {
  61. _timeout = INFINITE;
  62. }
  63. void SetInterface(T* pInterface)
  64. {
  65. ::InterlockedExchangePointer(reinterpret_cast<void**>(&_pInterface), pInterface);
  66. }
  67. operator CSocketHandle*() throw()
  68. {
  69. return( &_socket );
  70. }
  71. CSocketHandle* operator->() throw()
  72. {
  73. return( &_socket );
  74. }
  75. bool IsOpen() const
  76. {
  77. return _socket.IsOpen();
  78. }
  79. bool CreateSocket(LPCTSTR pszHost, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  80. {
  81. return _socket.CreateSocket(pszHost, pszServiceName, nFamily, nType, uOptions);
  82. }
  83. bool ConnectTo(LPCTSTR pszHostName, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType)
  84. {
  85. return _socket.ConnectTo(pszHostName, pszRemote, pszServiceName, nFamily, nType);
  86. }
  87. void Close()
  88. {
  89. _socket.Close();
  90. }
  91. void SetReadTimeout(IN CONST DWORD &dwTimeout = INFINITE )
  92. {
  93. _timeout = dwTimeout;
  94. }
  95. DWORD Read(LPBYTE lpBuffer, DWORD dwSize, LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  96. {
  97. return _socket.Read(lpBuffer, dwSize, lpAddrIn, dwTimeout);
  98. }
  99. DWORD Write(const LPBYTE lpBuffer, DWORD dwCount, const LPSOCKADDR lpAddrIn = NULL, DWORD dwTimeout = INFINITE)
  100. {
  101. return _socket.Write(lpBuffer, dwCount, lpAddrIn, dwTimeout);
  102. }
  103. bool StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0);
  104. void Terminate(DWORD dwTimeout = INFINITE);
  105. static bool IsConnectionDropped(DWORD dwError);
  106. protected:
  107. void Run();
  108. static DWORD WINAPI SocketClientProc(thisClass* _this);
  109. T* _pInterface;
  110. HANDLE _thread;
  111. CSocketHandle _socket;
  112. DWORD _timeout;
  113. };
  114. template <typename T, size_t tBufferSize>
  115. bool SocketClientImpl<T, tBufferSize>::StartClient(LPCTSTR pszHost, LPCTSTR pszRemote, LPCTSTR pszServiceName, int nFamily, int nType, UINT uOptions = 0)
  116. {
  117. // must be closed first...
  118. if ( IsOpen() ) return false;
  119. bool result = false;
  120. if ( nType == SOCK_STREAM )
  121. {
  122. result = _socket.ConnectTo(pszHost, pszRemote, pszServiceName, nFamily, nType); // TCP
  123. }
  124. else
  125. {
  126. // let provider select a port for us
  127. result = _socket.CreateSocket(pszHost, TEXT("0"), nFamily, nType, uOptions); // UDP
  128. }
  129. if ( result )
  130. {
  131. _thread = AtlCreateThread(SocketClientProc, this);
  132. if ( _thread == NULL )
  133. {
  134. DWORD dwError = GetLastError();
  135. _socket.Close();
  136. SetLastError(dwError);
  137. result = false;
  138. }
  139. }
  140. return result;
  141. }
  142. template <typename T, size_t tBufferSize>
  143. DWORD WINAPI SocketClientImpl<T, tBufferSize>::SocketClientProc(thisClass* _this)
  144. {
  145. if ( _this != NULL )
  146. {
  147. _this->Run();
  148. }
  149. return 0;
  150. }
  151. template <typename T, size_t tBufferSize>
  152. void SocketClientImpl<T, tBufferSize>::Run()
  153. {
  154. SockAddrIn addrIn;
  155. std::vector<unsigned char> data;
  156. data.resize( tBufferSize );
  157. DWORD dwRead;
  158. DWORD dwError;
  159. _ASSERTE( _pInterface != NULL && "Need an interface to pass events");
  160. // Notification: OnThreadBegin
  161. if ( _pInterface != NULL ) {
  162. _pInterface->OnThreadBegin(*this);
  163. }
  164. int type = _socket.GetSocketType();
  165. if (type == SOCK_STREAM) {
  166. _socket.GetPeerName( addrIn );
  167. }
  168. while ( _socket.IsOpen() )
  169. {
  170. if (type == SOCK_STREAM)
  171. {
  172. dwRead = _socket.Read(&data[0], tBufferSize, NULL, _timeout);
  173. }
  174. else
  175. {
  176. dwRead = _socket.Read(&data[0], tBufferSize, addrIn, _timeout);
  177. }
  178. if ( (dwRead != -1L) && (dwRead > 0))
  179. {
  180. // Notification: OnDataReceived
  181. if ( _pInterface != NULL ) {
  182. _pInterface->OnDataReceived(*this, &data[0], dwRead, addrIn);
  183. }
  184. }
  185. else if (type == SOCK_STREAM && dwRead == 0L )
  186. {
  187. // connection broken
  188. if ( _pInterface != NULL )
  189. {
  190. _pInterface->OnConnectionDropped(*this);
  191. }
  192. break;
  193. }
  194. else if ( dwRead == -1L )
  195. {
  196. dwError = GetLastError();
  197. if ( _pInterface != NULL )
  198. {
  199. if (IsConnectionDropped( dwError) ) {
  200. // Notification: OnConnectionDropped
  201. if (type == SOCK_STREAM || (dwError == WSAENOTSOCK || dwError == WSAENETDOWN))
  202. {
  203. _pInterface->OnConnectionDropped(*this);
  204. break;
  205. }
  206. }
  207. // Notification: OnConnectionError
  208. _pInterface->OnConnectionError(*this, dwError);
  209. }
  210. else
  211. {
  212. break;
  213. }
  214. }
  215. }
  216. data.clear();
  217. // Notification: OnThreadExit
  218. if ( _pInterface != NULL ) {
  219. _pInterface->OnThreadExit(*this);
  220. }
  221. }
  222. template <typename T, size_t tBufferSize>
  223. void SocketClientImpl<T, tBufferSize>::Terminate(DWORD dwTimeout /*= INFINITE*/)
  224. {
  225. _socket.Close();
  226. if ( _thread != NULL )
  227. {
  228. if ( WaitForSingleObject(_thread, dwTimeout) == WAIT_TIMEOUT ) {
  229. TerminateThread(_thread, 1);
  230. }
  231. CloseHandle(_thread);
  232. _thread = NULL;
  233. }
  234. }
  235. template <typename T, size_t tBufferSize>
  236. bool SocketClientImpl<T, tBufferSize>::IsConnectionDropped(DWORD dwError)
  237. {
  238. // see: winerror.h for definition
  239. switch( dwError )
  240. {
  241. case WSAENOTSOCK:
  242. case WSAENETDOWN:
  243. case WSAENETUNREACH:
  244. case WSAENETRESET:
  245. case WSAECONNABORTED:
  246. case WSAECONNRESET:
  247. case WSAESHUTDOWN:
  248. case WSAEHOSTDOWN:
  249. case WSAEHOSTUNREACH:
  250. return true;
  251. default:
  252. break;
  253. }
  254. return false;
  255. }
  256. #endif // __SOCKETCLIENTIMPL_20160228__