复件 SocketClientImpl.h 6.8 KB

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