ClientStage.cpp
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:11k
源码类别:

模拟服务器

开发平台:

C/C++

  1. #include "ClientStage.h"
  2. #include <assert.h>
  3. #include "ESClientUtils.h"
  4. #include "ESClientWin32Exception.h"
  5. #include "ESClientSocket.h"
  6. #include "ESClientException.h"
  7. #include "ProtocolProtocol.h"
  8. /*
  9.  * Using directives
  10.  */
  11. using OnlineGameLib::Win32::Output;
  12. using OnlineGameLib::Win32::OutPutInfo;
  13. using OnlineGameLib::Win32::ToString;
  14. using OnlineGameLib::Win32::_tstring;
  15. using OnlineGameLib::Win32::CException;
  16. using OnlineGameLib::Win32::CWin32Exception;
  17. using OnlineGameLib::Win32::CSocket;
  18. using OnlineGameLib::Win32::DumpData;
  19. using OnlineGameLib::Win32::CCriticalSection;
  20. CGameClient::CGameClient(
  21. CConnectManager &refConnectManager,
  22. const OnlineGameLib::Win32::_tstring &addressToConnectServer,
  23. unsigned short portToConnectServer,
  24. size_t maxFreeBuffers,
  25. size_t bufferSize /* = 1024 */
  26. )
  27.   : OnlineGameLib::Win32::CSocketClient(addressToConnectServer, portToConnectServer, maxFreeBuffers, bufferSize)
  28.   , m_theConnectManager(refConnectManager)
  29. {
  30. }
  31. CGameClient::CGameClient(
  32. CConnectManager &refConnectManager,
  33. size_t maxFreeBuffers,
  34. size_t bufferSize /* = 1024 */
  35. )
  36. : OnlineGameLib::Win32::CSocketClient(maxFreeBuffers, bufferSize)
  37. , m_theConnectManager(refConnectManager)
  38. {
  39. }
  40. CGameClient::~CGameClient()
  41. {
  42. try
  43. {
  44. ReleaseBuffers();
  45. }
  46. catch(...)
  47. {
  48. }
  49. }
  50. SOCKET CGameClient::CreateConnectionSocket( 
  51.   const OnlineGameLib::Win32::_tstring &addressToConnectServer,
  52.   unsigned short port)
  53. {
  54. SOCKET s = ::WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, 0 );
  55. if ( INVALID_SOCKET == s )
  56. {
  57. throw CWin32Exception( _T("CSocket::CreateListeningSocket()"), ::WSAGetLastError() );
  58. }
  59. CSocket connectionSocket( s );
  60. CSocket::InternetAddress localAddress( addressToConnectServer, port );
  61. connectionSocket.Connect( localAddress );
  62. return connectionSocket.Detatch();
  63. }
  64. void CGameClient::OnStartConnections()
  65. {
  66. /*
  67.  * OnStartConnections
  68.  */
  69. m_theConnectManager.ServerConnected();
  70. Output( _T("OnStartConnections") );
  71. }
  72. void CGameClient::OnStopConnections()
  73. {
  74. /*
  75.  * OnStopConnections
  76.  */
  77. m_theConnectManager.ServerDisConnected();
  78. Output( _T("OnStopConnections") );
  79. }
  80. void CGameClient::OnShutdownInitiated()
  81. {
  82. Output( _T("OnShutdownInitiated") );
  83. }
  84. void CGameClient::OnShutdownComplete()
  85. {
  86. Output( _T("OnShutdownComplete") );
  87. }
  88. void CGameClient::OnError( const OnlineGameLib::Win32::_tstring &message )
  89. {
  90. Output( _T("OnError - ") + message );
  91. }
  92. void CGameClient::OnConnect()
  93. {
  94. Output( _T("OnConnect") );
  95. }
  96. void CGameClient::OnClose()
  97. {
  98. Output( _T("OnClose") );
  99. }
  100. void CGameClient::ReadCompleted( OnlineGameLib::Win32::CIOBuffer *pBuffer )
  101. {
  102. try
  103. {
  104. const BYTE *pPackData = pBuffer->GetBuffer();
  105. const size_t used = pBuffer->GetUsed();
  106. m_theConnectManager.RecvFromServer( reinterpret_cast<const char*>( pPackData ), used );
  107. pBuffer->Empty();
  108. }
  109. catch(const CException &e)
  110. {
  111. Output( _T("ReadCompleted - Exception - ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  112. StopConnections();
  113. }
  114. catch(...)
  115. {
  116. Output( _T("ReadCompleted - Unexpected exception") );
  117. StopConnections();
  118. }
  119. }
  120. void CGameClient::PreWrite( 
  121. OnlineGameLib::Win32::CIOBuffer *pBuffer, 
  122. const char *pData, 
  123. size_t dataLength )
  124. {
  125. /*
  126.  * TODO : You can change protocol that it is used to split package
  127.  */
  128. if ( pBuffer && dataLength > 0 )
  129. {
  130. PACK_HEADER ph = {0};
  131. ph.cPackBeginFlag = PACK_BEGIN_FLAG;
  132. ph.cPackEndFlag = PACK_END_FLAG;
  133. ph.wDataLen = dataLength;
  134. ph.wCRCData = MAKE_CRC_DATE( PACK_BEGIN_FLAG, PACK_END_FLAG, dataLength );
  135. pBuffer->AddData( reinterpret_cast<const char *>(&ph), PACK_HEADER_LEN );
  136. }
  137. }
  138. /*
  139.  * class CConnectManager
  140.  */
  141. STDMETHODIMP CConnectManager::Startup()
  142. {
  143. HRESULT hr = E_FAIL;
  144. try
  145. {
  146. m_theGameClient.Start();
  147. hr = S_OK;
  148. }
  149. catch( const CException &e )
  150. {
  151. Output( _T("CConnectManager::Startup Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  152. }
  153. catch(...)
  154. {
  155. Output( _T("CConnectManager::Startup - Unexpected exception") );
  156. }
  157. return hr;
  158. }
  159. STDMETHODIMP CConnectManager::Cleanup()
  160. {
  161. HRESULT hr = E_FAIL;
  162. try
  163. {
  164. m_theGameClient.StopConnections();
  165. m_theGameClient.WaitForShutdownToComplete();
  166. hr = S_OK;
  167. }
  168. catch( const CException &e )
  169. {
  170. Output( _T("CConnectManager::Cleanup Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  171. }
  172. catch(...)
  173. {
  174. Output( _T("CConnectManager::Cleanup Unexpected exception") );
  175. }
  176. return hr;
  177. }
  178. STDMETHODIMP CConnectManager::ConnectTo(
  179. const char * const &pAddressToConnectServer, 
  180. unsigned short usPortToConnectServer )
  181. {
  182. HRESULT hr = E_FAIL;
  183. try
  184. {
  185. m_theGameClient.ConnectTo( pAddressToConnectServer, usPortToConnectServer );
  186. m_theGameClient.StartConnections();
  187. hr = S_OK;
  188. }
  189. catch( const CException &e )
  190. {
  191. Output( _T("Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  192. }
  193. catch(...)
  194. {
  195. Output( _T("Unexpected exception") );
  196. }
  197. return hr;
  198. }
  199. STDMETHODIMP CConnectManager::RegisterMsgFilter( 
  200. CALLBACK_CLIENT_EVENT pfnEventNotify )
  201. {
  202. m_pfnCallbackClientEvent = pfnEventNotify;
  203. return S_OK;
  204. }
  205. STDMETHODIMP CConnectManager::SendPackToServer(
  206. const void * const pData,
  207. const size_t &datalength )
  208. {
  209. m_theGameClient.Write( reinterpret_cast< const char* const >( pData ), datalength );
  210. return S_OK;
  211. }
  212. STDMETHODIMP_( const void * ) CConnectManager::GetPackFromServer( size_t &datalength )
  213. {
  214. CCriticalSection::Owner locker( m_csReadAction );
  215. m_pReadBuffer->Empty();
  216. m_pRecvBuffer = ProcessDataStream( m_pRecvBuffer );
  217. const BYTE *pPackData = m_pReadBuffer->GetBuffer();
  218. datalength = m_pReadBuffer->GetUsed();
  219. //[
  220. #ifdef NETWORK_DEBUG
  221. if ( datalength > 0 )
  222. {
  223. static const int sc_nFlagLen = sizeof(DWORD) * 2 + PACK_HEADER_LEN + sizeof(BYTE);
  224. assert( datalength > sc_nFlagLen && "Get error buffer from server!" );
  225. datalength -= sc_nFlagLen;
  226. }
  227. #endif //NETWORK_DEBUG
  228. //]
  229. return reinterpret_cast<const char*>( pPackData );
  230. }
  231. STDMETHODIMP CConnectManager::Shutdown()
  232. {
  233. m_theGameClient.StopConnections();
  234. return S_OK;
  235. }
  236. STDMETHODIMP CConnectManager::QueryInterface( REFIID riid, void** ppv )
  237. {
  238. /*
  239.  * By definition all COM objects support the IUnknown interface
  240.  */
  241. if( riid == IID_IUnknown )
  242. {
  243. AddRef();
  244. *ppv = dynamic_cast< IUnknown * >( this );
  245. }
  246. else if ( riid == IID_IESClient )
  247. {
  248. AddRef();
  249. *ppv = dynamic_cast< IClient * >( this );
  250. }
  251. else
  252. {
  253. *ppv = NULL;
  254. return E_NOINTERFACE;
  255. }
  256. return S_OK;
  257. }
  258.     
  259. STDMETHODIMP_(ULONG) CConnectManager::AddRef()
  260. {
  261. return InterlockedIncrement( &m_lRefCount );
  262. }
  263. STDMETHODIMP_(ULONG) CConnectManager::Release()
  264. {
  265. if ( InterlockedDecrement( &m_lRefCount ) > 0 )
  266. {
  267. return m_lRefCount;
  268. }
  269. delete this;
  270. return 0L;
  271. }
  272. CConnectManager::CConnectManager(
  273. size_t maxFreeBuffers, 
  274. size_t bufferSize /*1024*/ )
  275. : OnlineGameLib::Win32::CIOBuffer::Allocator(bufferSize, maxFreeBuffers)
  276. , m_lRefCount( 0L )
  277. , m_pfnCallbackClientEvent(NULL)
  278. , m_theGameClient( *this, MAX_BUFFER_KEEPINPOOL, EXTEND_BUFFER_SIZE )
  279. {
  280. m_pReadBuffer = Allocate();
  281. m_pRecvBuffer = Allocate();
  282. }
  283. CConnectManager::~CConnectManager()
  284. {
  285. m_pReadBuffer->Release();
  286. m_pRecvBuffer->Release();
  287. try
  288. {
  289. Flush();
  290. }
  291. catch(...)
  292. {
  293. }
  294. }
  295. void CConnectManager::ServerConnected()
  296. {
  297. if ( m_pfnCallbackClientEvent )
  298. {
  299. m_pfnCallbackClientEvent( SERVER_CONNECT_CREATE );
  300. }
  301. }
  302. void CConnectManager::ServerDisConnected()
  303. {
  304. if ( m_pfnCallbackClientEvent )
  305. {
  306. m_pfnCallbackClientEvent( SERVER_CONNECT_CLOSE );
  307. }
  308. }
  309. void CConnectManager::RecvFromServer( const char *pData, size_t dataLength )
  310. {
  311. CCriticalSection::Owner locker( m_csReadAction );
  312. m_pRecvBuffer->AddData( pData, dataLength );
  313. }
  314. void CConnectManager::ProcessCommand( const OnlineGameLib::Win32::CIOBuffer *pBuffer)
  315. {
  316. const BYTE *pPackData = pBuffer->GetBuffer();
  317. const size_t used = pBuffer->GetUsed();
  318. bool ok = false;
  319. WORD wDataLen = 0;
  320. PACK_HEADER ph = {0};
  321. if ( used > PACK_HEADER_LEN )
  322. {
  323. memcpy( &ph, pPackData, PACK_HEADER_LEN );
  324. wDataLen = ph.wDataLen;
  325. ok = true;
  326. }
  327. if ( ok )
  328. {
  329. const BYTE *pData = pPackData + PACK_HEADER_LEN;
  330. const size_t datalength = wDataLen;
  331. /*
  332.  * TODO : Process data receive from server
  333.  */
  334. //Output( _T("Get a package[length:") + ToString( wDataLen ) + _T("]n") + DumpData( pData, datalength, 50 ) );
  335. m_pReadBuffer->AddData( pData, datalength );
  336. }
  337. else
  338. {
  339. Output( "found error and close this connection!" );
  340. Shutdown();
  341. }
  342. }
  343. size_t CConnectManager::GetMinimumMessageSize() const
  344. {
  345. /*
  346.  * The smallest possible package we accept is pack-header
  347.  * once we have this many bytes we can start with try and work out
  348.  * what we have...
  349.  */
  350. return PACK_HEADER_LEN;
  351. }
  352. size_t CConnectManager::GetMessageSize( 
  353. const OnlineGameLib::Win32::CIOBuffer *pBuffer ) const
  354. {
  355. const BYTE *pData = pBuffer->GetBuffer();
  356. const size_t used = pBuffer->GetUsed();
  357. PACK_HEADER ph = {0};
  358. /*
  359.  * First, verify the flag of a message
  360.  */
  361. if ( used > PACK_HEADER_LEN )
  362. {
  363. memcpy( &ph, pData, PACK_HEADER_LEN );
  364. if ( PACK_BEGIN_FLAG == ph.cPackBeginFlag && 
  365.  PACK_END_FLAG == ph.cPackEndFlag )
  366. {
  367. WORD wCRC = MAKE_CRC_DATE( PACK_BEGIN_FLAG, PACK_END_FLAG, ph.wDataLen );
  368. if ( ph.wCRCData == wCRC )
  369. {
  370. return ph.wDataLen + PACK_HEADER_LEN;
  371. }
  372. }
  373. }
  374. return 0;
  375. }
  376. OnlineGameLib::Win32::CIOBuffer *CConnectManager::ProcessDataStream( 
  377. OnlineGameLib::Win32::CIOBuffer *pBuffer)
  378. {
  379. const size_t used = pBuffer->GetUsed();
  380. if ( used >= GetMinimumMessageSize() )
  381. {
  382. const size_t messageSize = GetMessageSize( pBuffer );
  383. if ( messageSize == 0 )
  384. {
  385. /*
  386.  * havent got a complete message yet.
  387.  * we null terminate our messages in the buffer, so we need to reserve
  388.  * a byte of the buffer for this purpose...
  389.  */
  390. if ( used == ( pBuffer->GetSize() - 1 ) )
  391. {
  392. Output( _T("Too much data!") );
  393. /*
  394.  * Write this message and then shutdown the sending side of the socket.
  395.  */
  396. Output( "found error and close this connection!" );
  397. Shutdown();
  398. /*
  399.  * throw the rubbish away
  400.  */
  401. pBuffer->Empty();
  402. }
  403. }
  404. else if ( used == messageSize )
  405. {
  406. Output( _T("Got a complete message and begin to process it") );
  407. /*
  408.  * we have a whole, distinct, message
  409.  */
  410. ProcessCommand( pBuffer );
  411. pBuffer->Empty();
  412. }
  413. else if (used > messageSize)
  414. {
  415. Output(_T("Got message plus extra data"));
  416. /*
  417.  * we have a message, plus some more data
  418.  * 
  419.  * allocate a new buffer, copy the extra data into it and try again...
  420.  */
  421. OnlineGameLib::Win32::CIOBuffer *pMessage = pBuffer->SplitBuffer( messageSize );
  422. ProcessCommand( pMessage );
  423. pMessage->Release();
  424. }
  425. }
  426. /*
  427.  * Reissue a read into the same buffer to collect more data
  428.  */
  429. return pBuffer;
  430. }