哪位朋友搞过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小时内删除。