不死鸟P2P

关于不死鸟 UT库 Phoenix库 ETUdp库 UTS库 库使用示范 最新进展 开发历史 下    载 授    权 联系我们
Phoenix库使用示范

[1]Phoenix库的引入

[2]无中心协议的设计

[3]数据处理接口

[4]其他代码分析

[5]编译和其他

 

[4]其他代码分析

为了保存不同节点的参数,我们需要事先定义好数据结构,注意下面的imyshakecode iyourshakecode,这是为了区别不同的连接,因为,可能当您发送数据的时候,您必须要提供该连接节点的shakecode.

//最简单的数据结构 用来保存每一个连接通道对方的详细信息 您可以扩充协议 添加更多的内容
struct Struct_NetPeersUser
{
bool bactive;
unsigned char uattr;//主动 1 被动2 扩展 3
unsigned __int16 imyshakecode;
unsigned __int16 iyourshakecode;
unsigned __int16 iattribute;
char s_username[129];
char s_nickname[129];
};

//我们自己的定义参数
struct Struct_MySetting
{
//主动连接通道数量
unsigned __int16 iportchannel;
//被动连接通道数量
unsigned __int16 ipasvchannel;
//扩展通道数量[临时连接]
unsigned __int16 iextchannel;
//实际总的通道数量
unsigned __int16 imaxchannel;
unsigned __int16 iattribute;
char s_myname[129];
char s_mynickname[129];

};

下面是2个非常关键的函数

分别是尝试启动 和 停止运行

// 尝试启动
const bool CNetFriendsDlg::TryStartRun(__int32 * piresult)
{
if(this->mb_run)
return true;
mb_new=false;
this->arr_channel.clear( );
this->arr_info.clear( );
this->arr_channel.reserve(1024);
this->arr_info.reserve(1024);
//尝试初始化 并启动吧
//首先分配内存吧
//首先弹出设置对话框吧
CSetDlg1 dlg;
dlg.iextchannel=this->m_set.iextchannel;
dlg.ipasvchannel=this->m_set.ipasvchannel;
dlg.iportchannel=this->m_set.iportchannel;
//执行转换
wchar_t ubuff[2001];
memset(ubuff,0,2001*sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0,this->m_set.s_myname,-1,ubuff,2000 );
dlg.ms_username=ubuff;
ubuff[0]=L'\0';
MultiByteToWideChar(CP_UTF8, 0,this->m_set.s_mynickname,-1,ubuff,2000 );
dlg.ms_nickname=ubuff;

if(dlg.DoModal( )==IDOK)
{
//执行接收吧
this->m_set.iextchannel=dlg.iextchannel;
this->m_set.ipasvchannel=dlg.ipasvchannel;
this->m_set.iportchannel=dlg.iportchannel;

char buffs[2001];
memset(buffs,0,2001);
WideCharToMultiByte( CP_UTF8, 0, dlg.ms_username, -1,buffs, 1900, NULL, NULL );
if(buffs[0]!='\0' && strlen(buffs)<=128)
strcpy(this->m_set.s_myname,buffs);
buffs[0]='\0';
WideCharToMultiByte( CP_UTF8, 0, dlg.ms_nickname, -1,buffs, 1900, NULL, NULL );
if(buffs[0]!='\0' && strlen(buffs)<=128)
strcpy(this->m_set.s_mynickname,buffs);

}

//这里应该增加参数安全检测
if(this->m_set.iextchannel<=0 || this->m_set.iextchannel>100) this->m_set.iextchannel=50;
if(this->m_set.iportchannel<50 || this->m_set.iportchannel>800) this->m_set.iportchannel=500;
if(this->m_set.ipasvchannel<100 || this->m_set.ipasvchannel>1000) this->m_set.ipasvchannel=this->m_set.iportchannel+150;

//注意 用户名中不允许使用通配字符 *
if(this->m_set.s_myname[0]=='\0'|| strchr(this->m_set.s_myname,'*')!=NULL ) strcpy(this->m_set.s_myname,"NetFriend");
if(this->m_set.s_mynickname[0]=='\0') strcpy(this->m_set.s_mynickname,"Hello kitty");

__int32 imax=this->m_set.iextchannel;
imax+=this->m_set.ipasvchannel;
imax+=this->m_set.iportchannel;

this->pnode=new struct Struct_NetPeersUser[imax];

if(this->pnode==NULL) return false; //failed to malloc memory

memset(pnode,0,imax * sizeof(struct Struct_NetPeersUser));

unsigned __int16 i;
for(i=0;i<imax;i++)
{
//这个初始化必须放在启动P2P核心前 虽然 false==0 但是为了提供一个可靠的流程 我们这里单独初始化一下
this->pnode[i].bactive=false;

}
//分配结构完成

/////////////////////////////////////

//首先需要创建这个phoenix core
this->pcore=::PX2_CreateP2PCore( );
if(this->pcore==NULL) return false;


//这里首先完成 回调函数的设置 请注意 这些函数当中均不可以有阻塞行为,也就是必须是立即完成模式 如果需要延迟处理 建议放入您自己的缓冲队列,使用postmessage 函数给自己一个消息 , 但是函数应该立即返回
::PX2_SetUpLayerCloseChannelFunc(pcore,::Local_CloseChannelFunc1);
::PX2_SetUpLayerDataTransferFunc(pcore, Local_DataTransferFunc1);
::PX2_SetUpLayerFirstLoginFunc(pcore,::Local_LoginMakeUserPassFunc1);
::PX2_SetUpLayerFirstRequestFunc(pcore,::Local_LoginRequestFunc1);
::PX2_SetUpLayerLastRequestFunc(pcore,::Local_LoginEndStepFunc1);
::PX2_SetUpLayerOpenChannelFunc(pcore,::Local_OpenChannelFunc1);
::PX2_SetUpLayerProcBroadCastFunc(pcore,::Local_ProcNormalPacket1); //可靠传输得到的数据包和不可靠传输得到的数据包 决定采用同一个函数处理 可以根据世纪需要分开处理 只是函数接口参数是完全相同的
::PX2_SetUpLayerProcNormalPacketFunc(pcore,::Local_ProcNormalPacket1);

//下面两个函数 当 底层完成了所有连接步骤的时候 调用 ,分别是被动和主动 由于我们这里被动和主动没有特殊意义 因此使用同一个函数执行
::PX2_SetPortConnectSuccFunc(pcore,LoginPortPasvModeSuccess1);
::PX2_SetPasvConnectSuccFunc(pcore,LoginPortPasvModeSuccess1);

//回调函数设置完成

::PX2_SetCoreBasicPara(pcore,this->m_set.iportchannel,this->m_set.ipasvchannel ,this->m_set.iextchannel,true,true,true/*true*/,true/*true*/);
::PX2_SetCoreNetPara(pcore,65108,65108,false,true); //端口号 分配 65108 注意,前一个是建议的端口号 后一个是给出协议使用端口号 在广播连接的时候使用
::PX2_SetCoreUnicode(pcore,1001);

//::PX2_SetCoreLicenseStr(pcore,STR_LICENSECODE);

//尝试启动核心吧
__int32 iresult=0;
if(::PX2_StartP2PCore(pcore,&iresult)==false)
{
return false;
}
else
{
//success
}
//由于授权以及设置原因 需要重新对齐实际的通道数量
this->m_set.imaxchannel=::PX2_GetCoreRealTotalChannel(pcore);
for(i=0;i<this->m_set.imaxchannel;i++)
{
//获取通道的实际属性
this->pnode[i].uattr=::PX2_GetCoreChannelAttribute(pcore,i);

}



//全部完成

//重新初始化列表吧
InitUserList( );

//为了避免大量连接导致频繁刷新 这里设置为2秒刷新一次
this->m_staticinfo.SetWindowTextW(L"Running...");

this->SetTimer(8822,2000,NULL);

this->mb_run=true;//是的 成功启动了

return true;


///////////////////////////////////////////////////////////////////////
}

// 停止运行
const void CNetFriendsDlg::TryStopRun(void)
{

if(this->pcore!=NULL)
{
::PX2_StopP2PCore(this->pcore);
::PX2_FreeP2PCore(pcore);
pcore=NULL;
}
if(this->pnode!=NULL)
{
delete []pnode;
pnode=NULL;
}

//初始化列表
this->m_listinfo.DeleteAllItems( );
this->m_listuser.DeleteAllItems( );

this->mb_run=false;

this->KillTimer(8822);
mb_new=false;

this->m_staticinfo.SetWindowTextW(L"");
return ;
}

界面部分的函数我们就不在这里解释了.

强调一点,回调函数绝对不可以阻塞,正是因为这个原因,我们采用了全局缓冲字符串池,而没有在数据处理函数中直接写界面.

Phoenix组网引擎,最开始,您可以使用广播方式,或者直接添加已经启动的其他节点的IP地址和端口,通常,只需要您成功连接任何一个已经组网的节点,通过自动扩散功能,在很短时间内就能完成与大多数节点的连接.

Phoenix组网和其他的P2P,例如日本的WINNY perfectDark等不同,日本的P2P采用的是层级结构,采用路由的方式,特点是多层加密路由,保密性好,这主要是为了应对日本那严格的P2P禁止令,缺点是对网络带宽要求极高,而且传输效率不好,几个关键节点中断,很容易导致局部的大范围中断. 而我们的采用的是PNP连接,直接点对点,与日本的P2P相反.



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
(c) 2011-2016 phoenixp2p.com