TCP.cpp
上传用户:popouu88
上传日期:2013-02-11
资源大小:2894k
文件大小:7k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. // TCP.cpp: implementation of the CTCP class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "TCP.h"
  5. #include "stdio.h"
  6. #pragma comment( lib , "ws2_32.lib")
  7. #define SINGLE_SOCKET        100
  8. #define MULTI_SOCKET         200
  9. #define HOST_NAME_LEHGTH     80
  10. //////////////////////////////////////////////////////////////////////
  11. // Construction/Destruction
  12. //////////////////////////////////////////////////////////////////////
  13. int CTCP::InitTCPNumber = 0;
  14. CTCP::CTCP() 
  15. {
  16. if( CTCP::InitTCPNumber == 0 )
  17. {
  18. WSADATA data;
  19. ::WSAStartup( MAKEWORD( 2 , 1 ) , &data );
  20. }
  21. CTCP::InitTCPNumber ++ ;
  22. this->s_listen = INVALID_SOCKET;
  23. this->connect_socket = INVALID_SOCKET;
  24. this->user_data = 0;
  25. this->visit = 0;
  26. ::InitializeCriticalSection( &this->session );
  27. }
  28. CTCP::~CTCP()
  29. {
  30. CTCP::InitTCPNumber -- ;
  31. if( CTCP::InitTCPNumber == 0 )
  32. ::WSACleanup( );
  33. ::DeleteCriticalSection( &this->session );
  34. }
  35. char * CTCP::GetIPAddressFromHostName( void )
  36. {
  37. char hostname[ HOST_NAME_LEHGTH ];
  38. ::gethostname( hostname , HOST_NAME_LEHGTH );
  39. hostent * ent = ::gethostbyname( hostname );
  40. sockaddr_in addr;
  41. memcpy( &addr.sin_addr , ent->h_addr , ent->h_length );
  42. return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
  43. }
  44. char * CTCP::GetPeerName( void )
  45. {
  46. sockaddr_in addr;
  47. int len = sizeof( addr );
  48. ::getpeername( this->connect_socket , ( SOCKADDR * )&addr , &len );
  49. return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
  50. }
  51. char * CTCP::GetSockName( void )
  52. {
  53. sockaddr_in addr;
  54. int len = sizeof( addr );
  55. ::getsockname( this->connect_socket , ( SOCKADDR * )&addr , &len );
  56. return ::inet_ntoa( *( in_addr * )&addr.sin_addr.s_addr );
  57. }
  58. bool CTCP::Create( void ( * OnAccept )( void *pContext , CTCP & server ) , void * pContext , const int port )
  59. {
  60. if( this == NULL ) return false;
  61. if( this->IsListen( ) ) return true;
  62. sockaddr_in addr;
  63. addr.sin_addr.s_addr = INADDR_ANY;
  64. addr.sin_family=AF_INET;
  65. addr.sin_port=::htons( port ); 
  66.     //创建套接字
  67.     SOCKET s = ::socket( AF_INET , SOCK_STREAM , IPPROTO_TCP );
  68. if(s == INVALID_SOCKET)
  69. {
  70. return false;
  71. }//绑定套接字
  72. if(::bind( s , ( SOCKADDR * )&addr,sizeof( addr ) ) == SOCKET_ERROR )
  73. {
  74. closesocket( s ); return false;
  75. }//监听套接字
  76. if( ::listen( s , 5 ) == SOCKET_ERROR )
  77. {
  78. closesocket( s ); return false;
  79. }
  80. this->s_listen = s;
  81. CInfo * info = new CInfo( OnAccept , pContext , this );
  82. CThread::Run( CTCP::OnAccept , info );
  83. return true;
  84. }
  85. void CTCP::OnAccept( void * pContext )
  86. {
  87. CInfo * info = ( CInfo * )pContext;
  88. sockaddr_in addr;
  89. int len=sizeof(addr);
  90. for( ; ; )
  91. {
  92. if( (  info->pThis->connect_socket = ::accept( info->pThis->s_listen , ( SOCKADDR * )&addr , &len ) ) == INVALID_SOCKET )
  93. break;
  94.         
  95. info->OnAccept( info->pContext , * info->pThis );
  96. }
  97. info->pThis->Close( );
  98. delete info;
  99. }
  100. bool CTCP::Accept( CTCP * client )
  101. {
  102. if( this == NULL || this->connect_socket == INVALID_SOCKET )
  103. return false;
  104. client->connect_socket = this->connect_socket;
  105.     
  106. this->connect_socket = INVALID_SOCKET;
  107. return true;
  108. }
  109. bool CTCP::Connect( const char * ip , const port )
  110. {
  111. if( this == NULL ) 
  112. return false;
  113. if( this->IsConnected( ) )
  114. return true;
  115. sockaddr_in addr;
  116. addr.sin_addr.s_addr=::inet_addr(ip);
  117. addr.sin_family=AF_INET;
  118. addr.sin_port=::htons(port); 
  119.     //创建套接字
  120. if( ( this->connect_socket = ::socket( AF_INET , SOCK_STREAM , IPPROTO_TCP) ) == INVALID_SOCKET )
  121. return false;
  122. //连接
  123. if( ::connect( this->connect_socket , ( SOCKADDR * )&addr , sizeof( addr ) ) == SOCKET_ERROR )
  124. {
  125. this->Close( ); return false;
  126. }
  127. return true;
  128. }
  129. bool CTCP::IsConnected( void )
  130. {
  131. return this->connect_socket != INVALID_SOCKET;
  132. }
  133. bool CTCP::Send( CBuffer & buffer )
  134. {
  135. if( ! this || ! this->IsConnected( ) )
  136. return false;
  137.     //锁定临界区
  138. ::EnterCriticalSection( &this->session );
  139. //保存缓冲区
  140. int s = 0 , size = *( int * )buffer.GetBuffer( );
  141.     //加密,后面的12个字节都填充ABC,表示头信息 
  142. char * now = buffer.GetBuffer( );
  143.     
  144. *( int * )now |= 0xABC00000;
  145.     //分次发送数据包
  146. fd_set fd;
  147. FD_ZERO( &fd );
  148. FD_SET( this->connect_socket , &fd );
  149.     //分次发送
  150. while( size > 0 && ::select( 0 , NULL , &fd , NULL , NULL ) > 0 && ( s = ::send( this->connect_socket , now , size , 0 ) ) > 0 )
  151. {
  152. size -= s;
  153. now += s;
  154. }//恢复信息
  155. *( int * )buffer.GetBuffer( ) ^= 0xABC00000;
  156.     //返回是否连接
  157. if( size > 0 )
  158. this->Close( );
  159. //解锁临界区
  160. ::LeaveCriticalSection( &this->session );
  161. return this->IsConnected( );
  162. }
  163. bool CTCP::Receive( CBuffer & buffer , struct timeval * timeout )
  164. {
  165. if( ! this || ! this->IsConnected( ) ) 
  166. return false;
  167. int s = 0 , size = 1;
  168. fd_set fd;
  169. FD_ZERO( &fd );
  170. FD_SET( this->connect_socket , &fd );
  171. //接收数据包的大小
  172. BYTE_INT_UNION BI;
  173. BI.iValue = 0;
  174.     //一次读取一个字节,读出数据包的大小
  175. while( ::select( 0 , &fd , NULL , NULL , timeout ) > 0 && ( size & 0xFFF00000 ) != 0xABC00000 )
  176. {   
  177. BI.B.a = BI.B.b; BI.B.b = BI.B.c; BI.B.c = BI.B.d;
  178. if( ::recv( this->connect_socket , ( char * )&BI.B.d , ( int )sizeof( BYTE ) , 0 ) <= 0 )
  179. {
  180. this->Close( ); break;
  181. }
  182. else
  183. size = BI.iValue;
  184. }//判断头标志,如果头标志接收错误,那么断开连接
  185. if( ( size & 0xFFF00000 ) == 0xABC00000 )
  186. { //取出要接收缓冲区的大小
  187. size ^= 0xABC00000; 
  188.         //重新分配内存
  189. if( buffer.GetSize( ) < size )
  190. buffer.Resize( size );
  191. char * now = buffer.GetBuffer( );
  192.         //保存大小且偏移4个字节 
  193. *( int * )now = size; now += sizeof( int ); size -= sizeof( int );
  194.         //循环接收数据
  195. while( size > 0 && ::select( 0 , &fd , NULL , NULL , NULL ) > 0 && ( s = ::recv( this->connect_socket , now , size , 0 ) ) > 0 )
  196. {
  197. now += s;
  198. size -= s;
  199. }
  200. }//接收过程中出错,那么不处理
  201. if( size > 0 )
  202. {
  203. buffer.Release( );
  204. size = 1;
  205.         //判断是否可以发送出去  
  206. if( ::send( this->connect_socket , ( char * )&size , ( int )sizeof( char ) , 0  ) <= 0 )
  207. this->Close( );
  208. else
  209. ::Sleep( 100 );
  210. }//返回是否连接
  211. return this->IsConnected( );
  212. }
  213. void CTCP::Close( void )
  214. {   //关闭监听
  215. SOCKET s;
  216. if( this->IsListen( ) )
  217. {
  218. s = this->s_listen;
  219. this->s_listen = INVALID_SOCKET;
  220. ::closesocket( s );
  221. }//关闭连接
  222. if( this->IsConnected( ) )
  223. {
  224. s = this->connect_socket;
  225. this->connect_socket = INVALID_SOCKET;
  226. ::closesocket( s );
  227. }
  228. }