关健字:
UDP
UDT
UDX
UDP文件传输
NAT,P2P,穿透
实现:
如今P2P NAT技术已经是比较成熟的技术,在网上也有很详细的原理及实现,但是,真正能稳定使用的代码却很少.或者是参数设置复杂,代码庸长,不便于项目实施.
UDX是一个比较方便使用的UDP库,可以利用接口简单设置,P2P服务器参数,超时,就可以完成P2P联接,让应用程序开发变得相当简单,我现在就UDX样例程中的P2PSENDFILE工程分析一下,主要的几个步骤.
1.设置P2P回调函授,这样,当P2P成功或超时时我们能得到通知.
代码片段1:
class CP2pSendFileDlg : public CDialog,
public IUdxFSink,//当有对方请求发送文件时,触发相关事件
public IUdxP2pSink,//当P2P事件发生回调
public ITransFormSink//当P2P不成功时,中转事件接口
{
我们把主界面,从这些接口派生,这样,可以接收到UDX内部发出的一些事件,这些事件是由UDX内部线程回调的.
别忘了关健的一部设置,回调关联,把UDX和我们的主界面关联起来.利用UDX的接口SetSink
2,设置P2P参数,进行P2P
代码片段2:
void CP2pSendFileDlg::OnButton2()
{
IUdxP2pClient * pP2pClient = m_pFileSend->GetP2pClient();//从UDX接口中查询到P2P接口
pP2pClient->SetNatServer(m_strP2pSver.GetBuffer(0),m_port);//设置 P2P 打洞中介服务器
pP2pClient->SetSink(this);//和主界面关联,关健,不然收不到UDX P2P成功的消息 了.
pP2pClient->Start();//开始进行P2P
if(pP2pClient->ConnectServer(m_userid.GetBuffer(0),m_desuserid.GetBuffer(0),(DWORD)this))//对用户1和用户2组成的字符串对进行P2P,并可以设置回调时的参数
{
}
3,处理P2P结果
一切准备就绪,当P2P发生时会做哪些事情呢?我们再来看代码
代码片段3
void CP2pSendFileDlg::OnP2pConnect( SOCKADDR addrRemote,int errocode,char* user1,char* user2,DWORD dwuser )
{//回调中有五个参数,分别是应用层比较关心的几个值 ,分别是,对方外网地址,错误码,用户1,用户2,进行P2P时协带的用户自定义指针
sockaddr_in *pAddr = (sockaddr_in*)&addrRemote;
char*ip = inet_ntoa(pAddr->sin_addr);
UDP_SHORT port = ntohs(pAddr->sin_port) ;
if(errocode == 0)//如果P2P成功,如果是发送端,就直联P2P成功的地址,因为已经被我们"打洞成功",所以,可以直接联接了
{
if(m_bSender)
{
if(m_pFileSend->Connect(ip,port,TRUE))//阻塞联接
{
m_pFileSend->SendFile(m_strFileName.GetBuffer(0));
}
SetTimer(101,1000,0);
}else
{
SetTimer(100,1000,0);
}
AfxGetMainWnd()->SetWindowText("p2p 成功");
}else//如果P2P不成功,转入中转模式,形式如何P2P过程
{
AfxGetMainWnd()->SetWindowText("p2p erro!");
if(m_bSender)
{
ITransFormClient * pTransFormClient = m_pFileSend->GetITransFormClient();//得到UDX的中转接口
pTransFormClient->AddMiddleServer(m_strMiddleSver.GetBuffer(0),2200);//设置中转服务器,可以设置多个
pTransFormClient->SetSink(this);//设置回调
pTransFormClient->RegisterClient(m_userid.GetBuffer(0), m_desuserid.GetBuffer(0),(DWORD)this);//注册中转用户对
pTransFormClient->Start();//开始注册
}else
{
ITransFormClient * pTransFormClient = m_pFileRecive->GetITransFormClient();
pTransFormClient->AddMiddleServer(m_strMiddleSver.GetBuffer(0),2200);
pTransFormClient->SetSink(this);
pTransFormClient->RegisterClient(m_userid.GetBuffer(0), m_desuserid.GetBuffer(0),(DWORD)this);
pTransFormClient->Start();
}
}
}
4,处理中转结果
中转回调事件
代码片段4:
void CP2pSendFileDlg::OnRegister(int errcode,DWORD streamid,char *user1,char* user2,DWORD dwUser)
{//UDX提供了五个参数,分别是错误码,流ID,用户1,用户2,及用户自定义数据
if(errcode != 0)
{
AfxGetMainWnd()->SetWindowText("OnRegister erro!");
return;
}
if(m_bSender)
{
m_pFileSend->SetTransformMSID(streamid);
if(m_pFileSend->Connect("127.0.0.1",1024,TRUE))//当注册成功时,联接的IP,PORT是任意的,可以忽略,随便什么都可以.
{
m_pFileSend->SendFile(m_strFileName.GetBuffer(0));
AfxGetMainWnd()->SetWindowText("发送中转成功");
}
SetTimer(101,1000,0);
}else
{
m_pFileRecive->SetTransformMSID(streamid);
SetTimer(100,1000,0);
AfxGetMainWnd()->SetWindowText("接收端中转成功");
}
}
运行结果
http://hi.csdn.net/attachment/201101/25/0_12959179993YNr.gif
以上代码可以在这里下載得到
http://www.goodudx.com/web/index.php/site/download/19