你的位置:pcMing工作室 >> 资讯 >> 编程开发 >> C++编程 >> 详细内容 在线投稿

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

排行榜 收藏 打印 发给朋友 举报 来源: 互联网   发布者:未知
热度2467票  浏览1006次 【共0条评论】【我要评论 时间:2010年4月08日 20:18
pcMing工作室qI6? H]d

pcMing工作室%kt;II,P6v

当有新的客户端连接到服务器时,服务器负责将该客户端的信息(IP地址、端口号)发送给其他客户端。pcMing工作室Z ^/k(_ l]5t4x5N6{

//
// 执行者:客户端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 ) );

	// 创建一个线程来侦听端口 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\n" );
	}
	// 对方断开连接了
	else
	{
		goto finished;
	}
	
	bRet = TRUE;
finished:
	g_pSock_MakeHole = NULL;
	return bRet;

}
pcMing工作室Hp-}2Q2`m r4Fe

顶:125 踩:148
对本文中的事件或人物打分:
当前平均分:-0.08 (786次打分)
对本篇资讯内容的质量打分:
当前平均分:-0.18 (698次打分)
【已经有710人表态】
109票
感动
80票
路过
89票
高兴
78票
难过
87票
搞笑
85票
愤怒
95票
无聊
87票
同情
上一篇 下一篇
发表评论
换一张

网友评论仅供网友表达个人看法,并不表明本网同意其观点或证实其描述。

查看全部回复【已有0位网友发表了看法】

网络资源