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相反.
|
|