哪位朋友搞过P2P的能说说怎么实现ClientA要求Server发送信息给ClientB向ClientA打洞?
原理大体知道点:
想实现ClientA与B通信,必须让Server通知ClientB向ClientA打洞,因为ClientA直接向B发送信息,出于安全考虑会被禁止的,所以在A向B通信之前,必须让B发送信息给A......
但是我不明白ClientB发送信息给A不一样会被A给禁止么?
你好,实现过程如下:
服务器端Server启动两个网络侦听。
客户端CilentA和客户端CilentB分别与服务器端Server保持联系。
当CilentA需要和CilentB建立直接的TCP连接时,首先连接服务器端Server的打洞端口,并发送协助连接申请。同时在该端口号上启动侦听。
SERVER连接收到CilentA的申请后通知CilentB,并将CilentA经过公网IP地址和端口等信息告诉CilentB。
CilentB收到服务器端Server的连接通知后首先与Server的打洞端口连接,随便发送一些数据后立即断开,这样做的目的是让服务器Server能知道CilentB的公网IP和端口号。
CilentB尝试与CilentA的公网IP地址和端口进行connect
客户端B打洞的同时在相同的端口上启动侦听。CilentB在一切准备就绪以后通过与服务器Server在收到以后将CilentB的公网IP和端口号告诉给CilentA。
CilentA收到服务器Server回复的CilentB的公网IP和端口号等信息以后,开始连接到CilentB公网IP和端口号,从而直接的TCP连接建立起来了。
// 服务器SERVER地址和端口号定义
#define SRV_TCP_MAIN_PORT 4000 // 服务器主连接的端口号
#define SRV_TCP_HOLE_PORT 8000 // 服务器响应客户端打洞申请的端口号
这两个端口是固定的,服务器Server启动时就开始侦听这两个端口了。
//
// 将新客户端登录信息发送给所有已登录的客户端,但不发送给自己printf怎么实现的
//
BOOL SendNewUserLoginNotifyToAll ( LPCTSTR lpszClientIP, UINT nClientPort, DWORD dwID )
{
ASSERT ( lpszClientIP && nClientPort > 0 );
g_CSFor_PtrAry_SockClient.Lock();
for ( int i=0; im_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\n", 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\n", hwFormatMessage(GetLastError()) );
goto finished;
}
UINT nOptValue = 1;
if ( !Sock.SetSockOpt ( SO_REUSEADDR, &nOptValue , sizeof(UINT) ) )
{
printf ( "SetSockOpt socket failed : %s\n", hwFormatMessage(GetLastError()) );
goto finished;
}
if ( !Sock.Bind ( 0 ) )
{
printf ( "Bind socket failed : %s\n", hwFormatMessage(GetLastError()) );
goto finished;
}
if ( !Sock.Connect ( g_pServerAddess, SRV_TCP_HOLE_PORT ) )
{
printf ( "Connect to [%s:%d] failed : %s\n", 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\n", szError );
goto finished;
}
g_pSock_MakeHole = &Sock;
ASSERT ( g_nHolePort == 0 );
VERIFY ( Sock.GetSockName ( csSocketAddress, g_nHolePort ) );
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论