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

模拟服务器

开发平台:

C/C++

  1. #include "jxserver.h"
  2. #include <winsock2.h>
  3. //[ Include in ...IPCPServer
  4. #include "IOCPServerException.h"
  5. #include "IOCPServerUtils.h"
  6. #include "IOCPServerManualResetEvent.h"
  7. //]
  8. //[ Include in ...Protocol
  9. #include "ProtocolProtocol.h"
  10. //]
  11. #include "GameServer.h"
  12. using OnlineGameLib::Win32::_tstring;
  13. using OnlineGameLib::Win32::CException;
  14. using OnlineGameLib::Win32::Output;
  15. using OnlineGameLib::Win32::CManualResetEvent;
  16. using OnlineGameLib::Win32::GetTimeStamp;
  17. using OnlineGameLib::Win32::OutPutInfo;
  18. using OnlineGameLib::Win32::ToString;
  19. using OnlineGameLib::Win32::CCriticalSection;
  20. using OnlineGameLib::Win32::DumpData;
  21. /*
  22.  * Server
  23.  */
  24. /*
  25.  * The still variable better than dynamic variable, because of don't to think that
  26.  * it can call through to unqualified virtual function
  27.  */
  28. static CGameServer g_theJXServer( MAX_SOCKET_KEEPINPOOL, MAX_BUFFER_KEEPINPOOL, EXTEND_BUFFER_SIZE );
  29. static CClientManager g_theClientManager( MAX_BUFFER_KEEPINPOOL, EXTEND_BUFFER_SIZE );
  30. /*
  31.  * Function
  32.  */
  33. bool ServerStartup( 
  34. JX_SERVER_
  35. unsigned long ulnAddressToListenOn,
  36. unsigned short usnPortToListenOn,
  37. bool bStartAtOnce
  38. )
  39. {
  40. bool ok = false;
  41. try
  42. {
  43. g_theJXServer.Open( ulnAddressToListenOn, usnPortToListenOn );
  44. if ( bStartAtOnce )
  45. {
  46. g_theJXServer.StartAcceptingConnections();
  47. }
  48. ok = true;
  49. }
  50. catch( const CException &e )
  51. {
  52. Output(_T("Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage());
  53. }
  54. catch(...)
  55. {
  56. Output(_T("Unexpected exception"));
  57. }
  58. return ok;
  59. }
  60. void ServerCleanup( JX_SERVER_ )
  61. {
  62. try
  63. {
  64. g_theJXServer.StopAcceptingConnections();
  65. g_theJXServer.WaitForShutdownToComplete();
  66. }
  67. catch( const CException &e )
  68. {
  69. Output(_T("Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage());
  70. }
  71. catch(...)
  72. {
  73. Output(_T("Unexpected exception"));
  74. }
  75. }
  76. void InstallCallBack( JX_SERVER_ CALLBACK_SERVER_EVENT pfn )
  77. {
  78. g_theClientManager.InstallCallBack( pfn );
  79. }
  80. void Server_Start()
  81. {
  82. g_theJXServer.StartAcceptingConnections();
  83. }
  84. void Server_Pause()
  85. {
  86. g_theJXServer.StopAcceptingConnections();
  87. }
  88. void Server_Begin()
  89. {
  90. g_theClientManager.PrepareToSend();
  91. }
  92. void Server_End()
  93. {
  94. g_theClientManager.BeginToSend();
  95. }
  96. void SendToClient(
  97. JX_SERVER_ 
  98. const unsigned long ulnID, 
  99. void *pData,
  100. size_t dataLength )
  101. {
  102. g_theClientManager.SendToClient( 
  103. ulnID,
  104. reinterpret_cast<const char*>( pData ), 
  105. dataLength );
  106. }
  107. void ShutdownClient(
  108. JX_SERVER_ 
  109. const unsigned long ulnID )
  110. {
  111. g_theClientManager.ShutdownClient( ulnID );
  112. }
  113. CClientManager::CClientManager(
  114. size_t maxFreeBuffers,
  115. size_t bufferSize /* = 1024 */)
  116. : OnlineGameLib::Win32::CIOBuffer::Allocator(bufferSize, maxFreeBuffers),
  117. m_pfnCallBackServerEvent( NULL )
  118. {
  119. int i=0;
  120. for ( i=0; i<MAX_CLIENT_CANBELINKED; i++ )
  121. {
  122. m_freeClientStack.push( i );
  123. }
  124. for ( i=0; i<MAX_CLIENT_CANBELINKED; i++ )
  125. {
  126. m_clientContext[i].pSocket = NULL;
  127. m_clientContext[i].pRecvBuffer = Allocate();
  128. m_clientContext[i].pReadBuffer = Allocate();
  129. m_clientContext[i].pWriteBuffer = Allocate();
  130. }
  131. }
  132. CClientManager::~CClientManager()
  133. {
  134. CCriticalSection::Owner lock( m_csAction );
  135. /*
  136.      * Repeat until stack is empty
  137.  */
  138. while ( !m_freeClientStack.empty() )
  139. {
  140. m_freeClientStack.pop();
  141. }
  142. m_usedClientStack.erase( m_usedClientStack.begin(), m_usedClientStack.end() );
  143. for ( int i=0; i<MAX_CLIENT_CANBELINKED; i++ )
  144. {
  145. m_clientContext[i].pReadBuffer->Release();
  146. m_clientContext[i].pRecvBuffer->Release();
  147. m_clientContext[i].pWriteBuffer->Release();
  148. }
  149. try
  150. {
  151. Flush();
  152. }
  153. catch(...)
  154. {
  155. }
  156. }
  157. unsigned long CClientManager::AddClient( 
  158. OnlineGameLib::Win32::CSocketServer::Socket *pSocket )
  159. {
  160. CCriticalSection::Owner lock( m_csAction );
  161. unsigned long index = -1;
  162. if ( !m_freeClientStack.empty() && pSocket )
  163. {
  164. /*
  165.  * Get ID from the free table
  166.  */
  167. index = m_freeClientStack.top();
  168. m_freeClientStack.pop();
  169. /*
  170.  * Set ID into the used table
  171.  */
  172. m_usedClientStack.push_back( index );
  173. /*
  174.  * Store information
  175.  */
  176. pSocket->SetUserData( index );
  177. m_clientContext[index].pSocket = pSocket;
  178. if ( m_pfnCallBackServerEvent )
  179. {
  180. m_pfnCallBackServerEvent( index, CLIENT_CONNECT_CREATE );
  181. }
  182. Output( GetTimeStamp() + _T("Add a client [ID:") + 
  183. ToString( index ) + _T( "] current total is " ) +
  184. ToString( m_usedClientStack.size() )
  185. );
  186. }
  187. return index;
  188. }
  189. unsigned long CClientManager::DelClient( 
  190. OnlineGameLib::Win32::CSocketServer::Socket *pSocket )
  191. {
  192. CCriticalSection::Owner lock( m_csAction );
  193. unsigned long index = -1;
  194. if ( !m_usedClientStack.empty() && pSocket )
  195. {
  196. index = pSocket->GetUserData();
  197. m_clientContext[index].pSocket = NULL;
  198. m_clientContext[index].pReadBuffer->Empty();
  199. m_clientContext[index].pRecvBuffer->Empty();
  200. m_clientContext[index].pWriteBuffer->Empty();
  201. /*
  202.  * Call back ID into the free table
  203.  */
  204. m_freeClientStack.push( index );
  205. /*
  206.  * Erase ID from the used table
  207.  */
  208. m_usedClientStack.remove( index );
  209. if ( m_pfnCallBackServerEvent )
  210. {
  211. m_pfnCallBackServerEvent( index, CLIENT_CONNECT_CLOSE );
  212. }
  213. Output( GetTimeStamp() + _T("Del a client [ID:") + 
  214. ToString( index ) + _T( "] current total is " ) + 
  215. ToString( m_usedClientStack.size() ) );
  216. }
  217. return index;
  218. }
  219. void CClientManager::SendToClient(
  220. const unsigned long ulnID, 
  221. const char *pData,
  222. size_t dataLength )
  223. {
  224. if ( ulnID >= 0 && ulnID < MAX_CLIENT_CANBELINKED )
  225. {
  226. OnlineGameLib::Win32::CSocketServer::Socket *pSocket = 
  227. m_clientContext[ulnID].pSocket;
  228. if ( pSocket )
  229. {
  230. try
  231. {
  232. m_clientContext[ulnID].pWriteBuffer->AddData( pData, dataLength );
  233. }
  234. catch(const CException &e)
  235. {
  236. Output(_T("Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage());
  237. pSocket->Shutdown();
  238. }
  239. catch(...)
  240. {
  241. Output(_T("CClientManager::SendToClient - Unexpected exception"));
  242. pSocket->Shutdown();
  243. }
  244. }
  245. }
  246. }
  247. void CClientManager::RecvFromClient(
  248.    const unsigned long ulnID, 
  249.    const char *pData,
  250.    size_t dataLength )
  251. {
  252. if ( ulnID >= 0 && ulnID < MAX_CLIENT_CANBELINKED )
  253. {
  254. OnlineGameLib::Win32::CSocketServer::Socket *pSocket = 
  255. m_clientContext[ulnID].pSocket;
  256. if ( pSocket )
  257. {
  258. m_clientContext[ulnID].pRecvBuffer->AddData( pData, dataLength );
  259. }
  260. }
  261. }
  262. const char *CClientManager::GetFromClient(
  263. const unsigned long ulnID, 
  264. size_t &dataLength )
  265. {
  266. if ( ulnID >= 0 && ulnID < MAX_CLIENT_CANBELINKED )
  267. {
  268. OnlineGameLib::Win32::CSocketServer::Socket *pSocket = 
  269. m_clientContext[ulnID].pSocket;
  270. if ( pSocket )
  271. {
  272. m_clientContext[ulnID].pReadBuffer->Empty();
  273. m_clientContext[ulnID].pRecvBuffer = ProcessDataStream(
  274. ulnID,
  275. m_clientContext[ulnID].pRecvBuffer );
  276. const BYTE *pPackData = m_clientContext[ulnID].pReadBuffer->GetBuffer();
  277. dataLength = m_clientContext[ulnID].pReadBuffer->GetUsed();
  278.  
  279. return reinterpret_cast<const char*>( pPackData );
  280. }
  281. }
  282. dataLength = 0;
  283. return NULL;
  284. }
  285. void CClientManager::ShutdownClient( const unsigned long ulnID )
  286. {
  287. if ( ulnID >= 0 && ulnID < MAX_CLIENT_CANBELINKED )
  288. {
  289. OnlineGameLib::Win32::CSocketServer::Socket *pSocket = 
  290. m_clientContext[ulnID].pSocket;
  291. if ( pSocket )
  292. {
  293. pSocket->Close();
  294. pSocket = NULL;
  295. m_clientContext[ulnID].pReadBuffer->Empty();
  296. m_clientContext[ulnID].pRecvBuffer->Empty();
  297. m_clientContext[ulnID].pWriteBuffer->Empty();
  298. }
  299. }
  300. }
  301. void CClientManager::PrepareToSend()
  302. {
  303. CCriticalSection::Owner lock( m_csAction );
  304. }
  305. void CClientManager::BeginToSend()
  306. {
  307. CCriticalSection::Owner lock( m_csAction );
  308. for ( LIST::iterator i = m_usedClientStack.begin(); 
  309. i != m_usedClientStack.end();
  310. i ++ )
  311. {
  312. unsigned long ulnID = *i;
  313. //[
  314. #ifdef NETWORK_DEBUG
  315. static const DWORD dwEOSFlag = 0xABCD0000; // End of stream
  316. m_clientContext[ulnID].pWriteBuffer->AddData( reinterpret_cast<const char*>( &dwEOSFlag ), sizeof(DWORD) );
  317. #endif  //NETWORK_DEBUG
  318. //]
  319. const BYTE *pPackData = m_clientContext[ulnID].pWriteBuffer->GetBuffer();
  320. size_t used = m_clientContext[ulnID].pWriteBuffer->GetUsed();
  321. //const size_t used = m_clientContext[ulnID].pWriteBuffer->GetUsed();
  322. //[
  323. #ifdef NETWORK_DEBUG //add by spe
  324. if (used <= 4)
  325. {
  326. used = 0;
  327. }
  328. #endif
  329. //]
  330. m_clientContext[ulnID].pSocket->Write( reinterpret_cast<const char*>( pPackData ), used );
  331. if ( used > 0 )
  332. {
  333. Output(
  334. _T("ID:") + 
  335. ToString(ulnID) + 
  336. _T(" - Package[length:") + 
  337. ToString( used ) + 
  338. _T("]n") + 
  339. DumpData( pPackData, used, 40 ) 
  340. );
  341. }
  342. m_clientContext[ulnID].pWriteBuffer->Empty();
  343. }
  344. }
  345. size_t CClientManager::GetClientCount()
  346. {
  347. CCriticalSection::Owner lock( m_csAction );
  348. return m_usedClientStack.size();
  349. }
  350. size_t GetClientCount()
  351. {
  352. return g_theClientManager.GetClientCount();
  353. }
  354. unsigned long AddClient( 
  355. OnlineGameLib::Win32::CSocketServer::Socket *pSocket )
  356. {
  357. return g_theClientManager.AddClient( pSocket );
  358. }
  359. unsigned long DelClient( 
  360. OnlineGameLib::Win32::CSocketServer::Socket *pSocket )
  361. {
  362. return g_theClientManager.DelClient( pSocket );
  363. }
  364. void CClientManager::ProcessCommand(
  365.    const unsigned long ulnID,
  366.    const OnlineGameLib::Win32::CIOBuffer *pBuffer) const
  367. {
  368. const BYTE *pPackData = pBuffer->GetBuffer();
  369. const size_t used = pBuffer->GetUsed();
  370. bool ok = false;
  371. WORD wDataLen = 0;
  372. PACK_HEADER ph = {0};
  373. if ( used > PACK_HEADER_LEN )
  374. {
  375. memcpy( &ph, pPackData, PACK_HEADER_LEN );
  376. wDataLen = ph.wDataLen;
  377. ok = true;
  378. }
  379. if ( ok )
  380. {
  381. const BYTE *pData = pPackData + PACK_HEADER_LEN;
  382. const size_t datalength = wDataLen;
  383. /*
  384.  * TODO : Process data receive from client
  385.  */
  386. Output( _T("Get a package[length:") + ToString( wDataLen ) + _T("]n") + DumpData( pData, datalength, 40 ) );
  387. m_clientContext[ulnID].pReadBuffer->AddData( pData, datalength );
  388. }
  389. else
  390. {
  391. Output( "found error and close this socket!" );
  392. m_clientContext[ulnID].pSocket->Close();
  393. }
  394. }
  395. size_t CClientManager::GetMinimumMessageSize() const
  396. {
  397. /*
  398.  * The smallest possible package we accept is pack-header
  399.  * once we have this many bytes we can start with try and work out
  400.  * what we have...
  401.  */
  402. return PACK_HEADER_LEN;
  403. }
  404. size_t CClientManager::GetMessageSize(
  405. const OnlineGameLib::Win32::CIOBuffer *pBuffer ) const
  406. {
  407. const BYTE *pData = pBuffer->GetBuffer();
  408. const size_t used = pBuffer->GetUsed();
  409. PACK_HEADER ph = {0};
  410. /*
  411.  * First, verify the flag of a message
  412.  */
  413. if ( used > PACK_HEADER_LEN )
  414. {
  415. memcpy( &ph, pData, PACK_HEADER_LEN );
  416. if ( PACK_BEGIN_FLAG == ph.cPackBeginFlag && 
  417.  PACK_END_FLAG == ph.cPackEndFlag )
  418. {
  419. WORD wCRC = MAKE_CRC_DATE( PACK_BEGIN_FLAG, PACK_END_FLAG, ph.wDataLen );
  420. if ( ph.wCRCData == wCRC )
  421. {
  422. return ph.wDataLen + PACK_HEADER_LEN;
  423. }
  424. }
  425. }
  426. return 0;
  427. }
  428. OnlineGameLib::Win32::CIOBuffer *CClientManager::ProcessDataStream(
  429. const unsigned long ulnID,
  430. OnlineGameLib::Win32::CIOBuffer *pBuffer) const
  431. {
  432. const size_t used = pBuffer->GetUsed();
  433. if ( used >= GetMinimumMessageSize() )
  434. {
  435. const size_t messageSize = GetMessageSize( pBuffer );
  436. if ( messageSize == 0 )
  437. {
  438. /*
  439.  * havent got a complete message yet.
  440.  * we null terminate our messages in the buffer, so we need to reserve
  441.  * a byte of the buffer for this purpose...
  442.  */
  443. if ( used == ( pBuffer->GetSize() - 1 ) )
  444. {
  445. Output( _T("Too much data!") );
  446. /*
  447.  * Write this message and then shutdown the sending side of the socket.
  448.  */
  449. Output( "found error and close this socket!" );
  450. m_clientContext[ulnID].pSocket->Close();
  451. /*
  452.  * throw the rubbish away
  453.  */
  454. pBuffer->Empty();
  455. }
  456. }
  457. else if ( used == messageSize )
  458. {
  459. Output( _T("Got complete, distinct, message") );
  460. /*
  461.  * we have a whole, distinct, message
  462.  */
  463. ProcessCommand( ulnID, pBuffer );
  464. pBuffer->Empty();
  465. }
  466. else if ( used > messageSize )
  467. {
  468. Output( _T("Got message plus extra data") );
  469. /*
  470.  * we have a message, plus some more data
  471.  * 
  472.  * allocate a new buffer, copy the extra data into it and try again...
  473.  */
  474. OnlineGameLib::Win32::CIOBuffer *pMessage = 
  475. pBuffer->SplitBuffer( messageSize );
  476. ProcessCommand( ulnID, pMessage );
  477. pMessage->Release();
  478. }
  479. }
  480. /*
  481.  * Reissue a read into the same buffer to collect more data
  482.  */
  483. return pBuffer;
  484. }
  485. void RecvFromClient( 
  486. JX_SERVER_ 
  487. const unsigned long ulnID,
  488. const char *pData, 
  489. size_t dataLength )
  490. {
  491. g_theClientManager.RecvFromClient( ulnID, pData, dataLength );
  492. }
  493. const char *GetFromClient(
  494. const unsigned long ulnID, 
  495. size_t &dataLength )
  496. {
  497. return g_theClientManager.GetFromClient( ulnID, dataLength );
  498. }