WEB开发网
开发学院软件开发VC TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞 阅读

TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞

 2010-07-25 20:46:50 来源:WEB开发网   
核心提示:整个实现过程靠文字恐怕很难讲清楚,再加上我的语言表达能力很差(高考语文才考75分,TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞(3),总分150分,惭愧),申请与客户端B建立直接的TCP连接//BOOL Handle_NewUserLogin ( CSocket &MainSock, t_NewUserLo

整个实现过程靠文字恐怕很难讲清楚,再加上我的语言表达能力很差(高考语文才考75分,总分150分,惭愧),所以只好用代码来说明问题了。

// 服务器地址和端口号定义
#define SRV_TCP_MAIN_PORT    4000  // 服务器主连接的端口号
#define SRV_TCP_HOLE_PORT    8000  // 服务器响应客户端打洞申请的端口号
这两个端口是固定的,服务器S启动时就开始侦听这两个端口了。//
// 将新客户端登录信息发送给所有已登录的客户端,但不发送给自己
//
BOOL SendNewUserLoginNotifyToAll ( LPCTSTR lpszClientIP, UINT nClientPort, DWORD dwID )
{
   ASSERT ( lpszClientIP && nClientPort > 0 );
   g_CSFor_PtrAry_SockClient.Lock();
   for ( int i=0; i<g_PtrAry_SockClient.GetSize(); i++ )
   {
     CSockClient *pSockClient = (CSockClient*)g_PtrAry_SockClient.GetAt(i);
     if ( pSockClient && pSockClient->m_bMainConn && pSockClient->m_dwID > 0 && pSockClient->m_dwID != dwID )
     {
       if ( !pSockClient->SendNewUserLoginNotify ( lpszClientIP, nClientPort, dwID ) )
       {
         g_CSFor_PtrAry_SockClient.Unlock();
         return FALSE;
       }
     }
   }
   g_CSFor_PtrAry_SockClient.Unlock ();
   return TRUE;
}
当有新的客户端连接到服务器时,服务器负责将该客户端的信息(IP地址、端口号)发送给其他客户端。//
// 执行者:客户端A
// 有新客户端B登录了,我(客户端A)连接服务器端口 SRV_TCP_HOLE_PORT ,申请与客户端B建立直接的TCP连接
//
BOOL Handle_NewUserLogin ( CSocket &MainSock, t_NewUserLoginPkt *pNewUserLoginPkt )
{
   printf ( "New user ( %s:%u:%u ) login server
", pNewUserLoginPkt->szClientIP,
     pNewUserLoginPkt->nClientPort, pNewUserLoginPkt->dwID );
   BOOL bRet = FALSE;
   DWORD dwThreadID = 0;
   t_ReqConnClientPkt ReqConnClientPkt;
   CSocket Sock;
   CString csSocketAddress;
   char szRecvBuffer[NET_BUFFER_SIZE] = {0};
   int nRecvBytes = 0;
   // 创建打洞Socket,连接服务器协助打洞的端口号 SRV_TCP_HOLE_PORT
   try
   {
     if ( !Sock.Socket () )
     {
       printf ( "Create socket failed : %s
", hwFormatMessage(GetLastError()) );
       goto finished;
     }
     UINT nOptValue = 1;
     if ( !Sock.SetSockOpt ( SO_REUSEADDR, &nOptValue , sizeof(UINT) ) )
     {
       printf ( "SetSockOpt socket failed : %s
", hwFormatMessage(GetLastError()) );
       goto finished;
     }
     if ( !Sock.Bind ( 0 ) )
     {
       printf ( "Bind socket failed : %s
", hwFormatMessage(GetLastError()) );
       goto finished;
     }
     if ( !Sock.Connect ( g_pServerAddess, SRV_TCP_HOLE_PORT ) )
     {
       printf ( "Connect to [%s:%d] failed : %s
", g_pServerAddess,
         SRV_TCP_HOLE_PORT, hwFormatMessage(GetLastError()) );
       goto finished;
     }
   }
   catch ( CException e )
   {
     char szError[255] = {0};
     e.GetErrorMessage( szError, sizeof(szError) );
     printf ( "Exception occur, %s
", szError );
     goto finished;
   }
   g_pSock_MakeHole = &Sock;
   ASSERT ( g_nHolePort == 0 );
   VERIFY ( Sock.GetSockName ( csSocketAddress, g_nHolePort ) );
   // 创建一个线程来侦听端口 g_nHolePort 的连接请求
   dwThreadID = 0;
   g_hThread_Listen = ::CreateThread ( NULL, 0, ::ThreadProc_Listen, LPVOID(NULL), 0, &dwThreadID );
   if (!HANDLE_IS_VALID(g_hThread_Listen) ) return FALSE;
   Sleep ( 3000 );
   // 我(客户端A)向服务器协助打洞的端口号 SRV_TCP_HOLE_PORT 发送申请,希望与新登录的客户端B建立连接
   // 服务器会将我的打洞用的外部IP和端口号告诉客户端B
   ASSERT ( g_WelcomePkt.dwID > 0 );
   ReqConnClientPkt.dwInviterID = g_WelcomePkt.dwID;
   ReqConnClientPkt.dwInvitedID = pNewUserLoginPkt->dwID;
   if ( Sock.Send ( &ReqConnClientPkt, sizeof(t_ReqConnClientPkt) ) != sizeof(t_ReqConnClientPkt) )
     goto finished;
   // 等待服务器回应,将客户端B的外部IP地址和端口号告诉我(客户端A)
   nRecvBytes = Sock.Receive ( szRecvBuffer, sizeof(szRecvBuffer) );
   if ( nRecvBytes > 0 )
   {
     ASSERT ( nRecvBytes == sizeof(t_SrvReqDirectConnectPkt) );
     PACKET_TYPE *pePacketType = (PACKET_TYPE*)szRecvBuffer;
     ASSERT ( pePacketType && *pePacketType == PACKET_TYPE_TCP_DIRECT_CONNECT );
     Sleep ( 1000 );
     Handle_SrvReqDirectConnect ( (t_SrvReqDirectConnectPkt*)szRecvBuffer );
     printf ( "Handle_SrvReqDirectConnect end
" );
   }
   // 对方断开连接了
   else
   {
     goto finished;
   }
  
   bRet = TRUE;
finished:
   g_pSock_MakeHole = NULL;
   return bRet;
}

上一页  1 2 3 4 5 6  下一页

Tags:TCP 实现 PP

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接