SocketClient.cpp
Upload User: dzyhzl
Upload Date: 2019-04-29
Package Size: 56270k
Code Size: 13k
Development Platform:

C/C++

  1. #include "stdafx.h"
  2. #include "SocketClient.h"
  3. #include "Win32Exception.h"
  4. #include "Utils.h"
  5. #include "Socket.h"
  6. #include "Macro.h"
  7. #include <vector>
  8. #pragma comment(lib, "ws2_32.lib")
  9. /*
  10.  * Link options and warning
  11.  */
  12. #pragma message( "NOTE : --------------------OnlineGameLib [Client] : Announcement--------------------" )
  13. #pragma message( "NOTE : The lib be used for socket communicate that it is base on" )
  14. #pragma message( "NOTE : Windows 95 and Windows NT 3.51 and later" )
  15. #pragma message( "NOTE :" )
  16. #pragma message( "NOTE : liupeng xishanju.zhuhai.china 2003.1" )
  17. #pragma message( "NOTE : -----------------------------------------------------------------------------" )
  18. using std::vector;
  19. /*
  20.  * namespace OnlineGameLib::Win32
  21.  */
  22. namespace OnlineGameLib {
  23. namespace Win32 {
  24. CSocketClient::CSocketClient(
  25. const _tstring &addressToConnectServer,
  26. unsigned short portToConnectServer,
  27. size_t maxFreeBuffers,
  28. size_t bufferSize /* = 1024 */
  29. )
  30.   : CIOBuffer::Allocator(bufferSize, maxFreeBuffers),
  31. m_address(addressToConnectServer),
  32. m_port(portToConnectServer),
  33. m_connectSocket(INVALID_SOCKET)
  34. {
  35. }
  36. CSocketClient::CSocketClient(
  37. size_t maxFreeBuffers,
  38. size_t bufferSize /* = 1024 */
  39. )
  40. : CIOBuffer::Allocator(bufferSize, maxFreeBuffers),
  41. m_port(0),
  42. m_connectSocket(INVALID_SOCKET)
  43. {
  44. }
  45. void CSocketClient::Connect(
  46.    const _tstring &addressToConnectServer,
  47.    unsigned short portToConnectServer
  48.    )
  49. {
  50. m_address = addressToConnectServer;
  51. m_port = portToConnectServer;
  52. }
  53. CSocketClient::~CSocketClient()
  54. {
  55. try
  56. {
  57. StopConnections();
  58. }
  59. catch(...)
  60. {
  61. TRACE( "CSocketClient::~CSocketClient() exception!" );
  62. }
  63. }
  64. bool CSocketClient::StartConnections()
  65. {
  66. CCriticalSection::Owner lock( m_criticalSection );
  67.     
  68. if ( INVALID_SOCKET == m_connectSocket )
  69. {
  70. /*
  71.  * Call to unqualified virtual function
  72.  */
  73. //OnStartConnections();
  74. /*
  75.  * call to unqualified virtual function
  76.  */
  77. m_connectSocket = CreateConnectionSocket( m_address, m_port );
  78. if ( !WaitAndVerifyCipher() )
  79. {
  80. return false;
  81. }
  82. m_eventSelect.AssociateEvent( m_connectSocket, FD_CONNECT | FD_CLOSE | FD_READ );
  83. m_successConnectionsEvent.Set();
  84. return true;
  85. }
  86. return false;
  87. }
  88. void CSocketClient::StopConnections()
  89. {
  90. CCriticalSection::Owner lock( m_criticalSection );
  91. if ( INVALID_SOCKET != m_connectSocket )
  92. {
  93. /*
  94.  * Change the sockH to be blocking
  95.  */
  96. /*
  97. DWORD dwIOCtlInfo = 0;
  98. if ( WSAIoctl( m_connectSocket, FIONBIO, &dwIOCtlInfo, sizeof( DWORD ),
  99.           NULL, 0, NULL, NULL, NULL ) )
  100. {
  101. OnError( _T("CSocketClient::StopAcceptingConnections() - WSAIoctl - ") + GetLastErrorMessage( ::WSAGetLastError() ) );
  102. }
  103. */
  104. /*
  105.  * Force an abortive close.
  106.  */
  107. LINGER lingerStruct;
  108. lingerStruct.l_onoff = 1;
  109. lingerStruct.l_linger = 0;
  110. if ( SOCKET_ERROR == ::setsockopt( m_connectSocket, 
  111. SOL_SOCKET, 
  112. SO_LINGER, 
  113. ( char * )&lingerStruct, 
  114. sizeof( lingerStruct ) ) )
  115. {
  116. OnError( _T("CSocketClient::setsockopt( SO_LINGER ) - ") + GetLastErrorMessage( ::WSAGetLastError() ) );
  117. }
  118. m_successConnectionsEvent.Reset();
  119. m_eventSelect.DissociateEvent();
  120. if ( 0 != ::closesocket( m_connectSocket ) )
  121. {
  122. /*
  123.  * Call to unqualified virtual function
  124.  */
  125. OnError( _T("CSocketClient::StopAcceptingConnections() - closesocket - ") + GetLastErrorMessage( ::WSAGetLastError() ) );
  126. }
  127. m_connectSocket = INVALID_SOCKET;
  128. /*
  129.  * Call to unqualified virtual function
  130.  */
  131. OnStopConnections();
  132. }
  133. }
  134. SOCKET CSocketClient::CreateConnectionSocket( 
  135.   const OnlineGameLib::Win32::_tstring &addressToConnectServer,
  136.   unsigned short port)
  137. {
  138. SOCKET s = ::WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, 0 );
  139. if ( INVALID_SOCKET == s )
  140. {
  141. throw CWin32Exception( _T("CSocket::CreateListeningSocket()"), ::WSAGetLastError() );
  142. }
  143. CSocket connectionSocket( s );
  144. CSocket::InternetAddress localAddress( addressToConnectServer, port );
  145. connectionSocket.Connect( localAddress );
  146. return connectionSocket.Detatch();
  147. }
  148. void CSocketClient::InitiateShutdown()
  149. {
  150. /*
  151.  * Signal that the dispatch thread should shut down all worker threads and then exit
  152.  */
  153. m_shutdownEvent.Set();
  154. StopConnections();
  155. /*
  156.  * Call to unqualified virtual function
  157.  */
  158. OnShutdownInitiated();
  159. }
  160. void CSocketClient::WaitForShutdownToComplete()
  161. {
  162. /*
  163.  * If we havent already started a shut down, do so...
  164.  */
  165. InitiateShutdown();
  166. Wait();
  167. }
  168. int CSocketClient::Run()
  169. {
  170. try
  171. {
  172. HANDLE handlesToWaitFor[2];
  173. handlesToWaitFor[0] = m_shutdownEvent.GetEvent();
  174. handlesToWaitFor[1] = m_successConnectionsEvent.GetEvent();
  175. while ( !m_shutdownEvent.Wait( 0 ) )
  176. {
  177. DWORD waitResult = ::WaitForMultipleObjects( 2, handlesToWaitFor, false, INFINITE );
  178. if ( waitResult == WAIT_OBJECT_0 )
  179. {
  180. /*
  181.  * Time to shutdown
  182.  */
  183. break;
  184. }
  185. else if ( waitResult == WAIT_OBJECT_0 + 1 )
  186. {
  187. /*
  188.  * Allocate a buffer for required read
  189.  */
  190. CIOBuffer *pReadContext = Allocate();
  191. while ( !m_shutdownEvent.Wait( 0 ) && m_successConnectionsEvent.Wait( 0 ) )
  192. {
  193. if ( m_eventSelect.WaitForEnumEvent( m_connectSocket, 1000 ) )
  194. {
  195. /*
  196.  * Find some events and process it
  197.  */
  198. /*
  199.  * A event to close
  200.  */
  201. if ( !m_eventSelect.Close() )
  202. {
  203. /*
  204.  * Call to unqualified virtual function
  205.  */
  206. StopConnections();
  207. //OnClose();
  208. }
  209. /*
  210.  * A event to read
  211.  */
  212. if ( !m_eventSelect.Read() )
  213. {
  214. OnRead( pReadContext );
  215. }
  216. /*
  217.  * A event to connect
  218.  */
  219. if ( !m_eventSelect.Connect() )
  220. {
  221. /*
  222.  * Call to unqualified virtual function
  223.  */
  224. OnStartConnections();
  225. //OnConnect();
  226. }
  227. /*
  228.  * A event to write
  229.  */
  230. /*
  231. if ( !m_eventSelect.Write() )
  232. {
  233. OnWrite();
  234. }*/
  235. if ( m_eventSelect.IsError() )
  236. {
  237. m_shutdownEvent.Set();
  238. StopConnections();
  239. /*
  240.  * Exit this thread
  241.  */
  242. break;
  243. }
  244. }
  245. } // while (...
  246. pReadContext->Release();
  247. }
  248. else
  249. {
  250. /*
  251.  * Call to unqualified virtual function
  252.  */
  253. OnError( _T("CSocketClient::Run() - WaitForMultipleObjects: ") + GetLastErrorMessage( ::GetLastError() ) );
  254. }
  255. } // while ( ... 
  256. }
  257. catch( const CWin32Exception &e )
  258. {
  259. /*
  260.  * Call to unqualified virtual function
  261.  */
  262. StopConnections();
  263. OnError( _T("CSocketClient::Run() - Exception: ") + e.GetWhere() + _T(" - ") + e.GetMessage() );
  264. _tstring sErrorInfo = e.GetMessage();
  265. //DEBUG_ONLY( Message( sErrorInfo.c_str() ) );
  266. }
  267. catch(...)
  268. {
  269. /*
  270.  * Call to unqualified virtual function
  271.  */
  272. StopConnections();
  273. OnError( _T("CSocketClient::Run() - Unexpected exception") );
  274. }
  275. /*
  276.  * Call to unqualified virtual function
  277.  */
  278. OnShutdownComplete();
  279. return 0;
  280. }
  281. void CSocketClient::ReleaseBuffers()
  282. {
  283. Flush();
  284. }
  285. void CSocketClient::OnError( const _tstring &message )
  286. {
  287. Output( message );
  288. }
  289. void CSocketClient::OnRead( CIOBuffer *pBuffer )
  290. {
  291. /*
  292.  * Determine the amount of data that can be read atomically from socket s
  293.  *
  294.  * ::WSAIoctl( s, FIONREAD, ...
  295.  */
  296. DWORD dwNumBytes = 0;
  297. DWORD dwFlags = 0;
  298. pBuffer->SetupRead();
  299. if ( SOCKET_ERROR == ::WSARecv(
  300. m_connectSocket,
  301. pBuffer->GetWSABUF(), 
  302. 1,
  303. &dwNumBytes, 
  304. &dwFlags,
  305. NULL,
  306. NULL ) )
  307. {
  308. DWORD lastError = ::WSAGetLastError();
  309. if ( ERROR_IO_PENDING != lastError )
  310. {
  311. _tstring sErrorInfo = GetLastErrorMessage( lastError );
  312. Output( _T("CSocketClient::OnRead() - WSARecv: ") + sErrorInfo );
  313. if ( lastError == WSAECONNABORTED || 
  314. lastError == WSAECONNRESET ||
  315. lastError == WSAEDISCON)
  316. {
  317. StopConnections();
  318. }
  319. }
  320. }
  321. else
  322. {
  323. pBuffer->Use( dwNumBytes );
  324. ReadCompleted( pBuffer );
  325. }
  326. }
  327. void CSocketClient::Write( const char *pData, size_t dataLength )
  328. {
  329. if ( INVALID_SOCKET != m_connectSocket &&
  330. dataLength > 0 &&
  331. pData )
  332. {
  333. CIOBuffer *pBuffer = Allocate();
  334. pBuffer->AddData( pData, dataLength );
  335. Write( pBuffer );
  336. pBuffer->Release();
  337. }
  338. }
  339. static struct timeval gs_CheckRW_timeout = { 5, 0 };
  340. void CSocketClient::Write( CIOBuffer *pBuffer )
  341. {
  342. size_t uDataLength = 0;
  343. if ( NULL == pBuffer ||
  344. ( 0 == ( uDataLength = pBuffer->GetUsed() ) ) ||
  345. INVALID_SOCKET == m_connectSocket )
  346. {
  347. return;
  348. }
  349. /*
  350.  * Begin to send data
  351.  */
  352. int nError = 0;
  353. DWORD lastError= 0;
  354. DWORD dwFlags = 0;
  355. DWORD dwSendNumBytes = 0;
  356. pBuffer->SetupWrite();
  357. WSABUF &wsa = *( pBuffer->GetWSABUF() );
  358. do
  359. {
  360. if ( SOCKET_ERROR != nError )
  361. {
  362. wsa.len -= dwSendNumBytes;
  363. wsa.buf += dwSendNumBytes;
  364. uDataLength -= dwSendNumBytes;
  365. nError = ::WSASend(
  366. m_connectSocket,
  367. &wsa, 
  368. 1, 
  369. &dwSendNumBytes,
  370. dwFlags,
  371. NULL, 
  372. NULL
  373. );
  374. if ( SOCKET_ERROR != nError && dwSendNumBytes >= uDataLength )
  375. {
  376. return;
  377. }
  378. }
  379. /*
  380.  * Continue to send buffer when 'dwSendNumBytes < uDataLength'
  381.  */
  382. if ( SOCKET_ERROR != nError )
  383. {
  384. continue;
  385. }
  386. /*
  387.  * Get error
  388.  */
  389. lastError = ::WSAGetLastError();
  390. if ( lastError == WSAECONNABORTED || 
  391.  lastError == WSAECONNRESET ||
  392.  lastError == WSAEDISCON )
  393. {
  394. _tstring sErrorInfo = GetLastErrorMessage( lastError );
  395. Output( _T("CSocketClient::Write() - WSASend: ") + sErrorInfo );
  396. StopConnections();
  397. return;
  398. }
  399. /*
  400.  * The other error what we don't process it
  401.  */
  402. if ( ( ERROR_IO_PENDING != lastError ) && 
  403.  ( WSAEWOULDBLOCK != lastError) )
  404. {
  405. _tstring sErrorInfo = GetLastErrorMessage( lastError );
  406. Output( _T("CSocketClient::Write() - WSASend: ") + sErrorInfo );
  407. return;
  408. }
  409. fd_set writefds;
  410. memset( &writefds, 0, sizeof( writefds ) );
  411. writefds.fd_count = 1;
  412. writefds.fd_array[0] = m_connectSocket;
  413. do
  414. {
  415. /*
  416.  * Check socket status
  417.  */
  418. nError = select( 1, NULL, &writefds, NULL, &gs_CheckRW_timeout );
  419. if ( SOCKET_ERROR == nError )
  420. {
  421. _tstring sErrorInfo = GetLastErrorMessage( lastError );
  422. Output( _T("CSocketClient::Write() - WSASend: ") + sErrorInfo );
  423. StopConnections();
  424. return;
  425. }
  426. /*
  427.  * It isn't time out
  428.  */
  429. if ( nError > 0 )
  430. {
  431. break;
  432. }
  433. /*
  434.  * If timeout
  435.  */
  436. if ( m_shutdownEvent.Wait( 0 ) )
  437. {
  438. return;
  439. }
  440. } while ( true );
  441. } while ( true );
  442. }
  443. static const DWORD g_dwTimeout = 1000;
  444. bool CSocketClient::WaitAndVerifyCipher()
  445. {
  446. fd_set fdRead  = { 0 };
  447. TIMEVAL stTime;
  448. TIMEVAL *pstTime = NULL;
  449. if ( INFINITE != g_dwTimeout ) 
  450. {
  451. stTime.tv_sec = g_dwTimeout;
  452. stTime.tv_usec = 0;
  453. pstTime = &stTime;
  454. }
  455. /*
  456.  * Select function set read timeout
  457.  */
  458. SOCKET s = ( SOCKET )m_connectSocket;
  459. DWORD dwTotalLength = 0;
  460. while ( true )
  461. {
  462. DWORD dwBytesRead = 0L;
  463. /*
  464.  * Set Descriptor
  465.  */
  466. FD_ZERO( &fdRead );
  467. FD_SET( s, &fdRead );
  468. int res = select( 0, &fdRead, NULL, NULL, pstTime );
  469. if ( res > 0)
  470. {
  471. res = recv( s, ( LPSTR )&m_theSendAccountBegin + dwTotalLength, sizeof( m_theSendAccountBegin ) - dwTotalLength, 0 );
  472. if ( res > 0 )
  473. {
  474. dwBytesRead = res;
  475. dwTotalLength += dwBytesRead;
  476. }
  477. }
  478. if ( res <= 0 )
  479. {
  480. /*
  481.  * Timeout and exit
  482.  */
  483. break;
  484. }
  485. if ( dwTotalLength == sizeof( m_theSendAccountBegin ) )
  486. {
  487. ACCOUNT_BEGIN *pAccountBegin = ( ACCOUNT_BEGIN * )( &m_theSendAccountBegin.AccountBegin );
  488. if ( pAccountBegin->ProtocolType == CIPHER_PROTOCOL_TYPE )
  489. {
  490. if ( pAccountBegin->Mode != 0 )
  491. {
  492. /*
  493. * Write this message and then shutdown the sending side of the socket.
  494. */
  495. Output( "Server send cliper mode error!" );
  496. if ( 0 != ::closesocket( m_connectSocket ) )
  497. {
  498. /*
  499. * Call to unqualified virtual function
  500. */
  501. OnError( _T("CSocketClient::StopAcceptingConnections() - closesocket - ") + GetLastErrorMessage( ::WSAGetLastError() ) );
  502. }
  503. m_connectSocket = INVALID_SOCKET;
  504. return false;
  505. }
  506. m_uKeyMode = pAccountBegin->Mode; 
  507. m_uServerKey = ~(pAccountBegin->ServerKey);
  508. m_uClientKey = ~(pAccountBegin->ClientKey);
  509. return true;
  510. }
  511. }
  512. }
  513. return false;
  514. }
  515. } // End of namespace OnlineGameLib
  516. } // End of namespace Win32