不死鸟P2P

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

[1]Phoenix库的引入

[2]无中心协议的设计

[3]数据处理接口

[4]其他代码分析

[5]编译和其他

 

[3]数据处理接口

Phoenix无中心组网库,采用的是回调函数来实现各种数据处理,虽然这很耗费系统资源,但是对于处理协议来说,这点开销不算什么,为了实现前面我们制定的无中心组网协议,我们需要定义我们的数据处理函数,如下:

//这里增加全局回调函数
//当需要发起或者接收一个新的连接的时候,调用本函数 参数分别是 通道下标 握手代码 是否是主动
static const bool _stdcall Local_OpenChannelFunc1(const __int32 ichannel, const unsigned __int16 shakecode , const bool bport )
{
TRACE(L"Login init function is called:%d\n",ichannel);
//始终返回真
pself->pnode[ichannel].bactive=false;
return true;
}
//当底层握手完毕 上层执行协议连接的时候调用 这是主动方发起的连接 然后发送上层的握手信息 返回打印的缓冲的实际长度 前一个16位是我们的握手码 后一个是对方的握手码 接下来一个 是我们接收到的缓冲长度
static const __int32 _stdcall Local_LoginMakeUserPassFunc1(const __int32 ichannel, const unsigned __int16 myshakecode,const unsigned __int16 yourshakecode, char * pmsg)
{
//这是主动发起方调用的
//也就是pcore发起的
//pself->iportchannel=ichannel;
//pself->iportshakecode=myshakecode;
//pself->iportyourshakecode=yourshakecode;
TRACE(L"Login 1 function is called...\n");
return sprintf_s(pmsg,1000,"HELO 1 %u *%s*%s",pself->m_set.iattribute,pself->m_set.s_myname,pself->m_set.s_mynickname);
}
//当底层握手完毕 接收到对方发送的请求完成上层连接的信息后,无论成功还是失败 都需要返回一组信息 返回打印的缓冲的实际长度 bool * 指出是连接成功还是连接失败 注意 如果成功 底层将改变连接状态为完成 否则为没有完成
static const __int32 _stdcall Local_LoginRequestFunc1(const __int32 ichannel, const unsigned __int16 myshakecode , const unsigned __int16 yourshakecode, const unsigned __int16 itxtsize ,const char * sask ,char * sanswer ,bool * psucc )
{
if(psucc!=NULL) *psucc=false;

TRACE(L"Login 2 function is called...\n");
if(itxtsize<=4) return -1;
int i1;
unsigned int ui2=0;
char scmds[16];
memset(scmds,0,16);
char username[129];
memset(username,0,129);
char nickname[129];
memset(nickname,0,129);

char buffs[1600];
memset(buffs,0,1600);
memcpy( buffs,sask,itxtsize);
char * pstart;
pstart=strchr(buffs,'*');
if(pstart==NULL) return -2;
*pstart='\0';
pstart++;
char * pend;
pend=strchr(pstart,'*');
if(pend==NULL) return -3;
*pend='\0';
pend++;
if(*pstart=='\0' || *pend=='\0') return -4;
//现在可以保证参数正确了



if(sscanf(sask,"%5s %d %u ",scmds,&i1,&ui2)!=3)
{
return -5;
}
if(strnicmp(scmds,"HELO",4)!=0)
{
return -6;
}
//要求i1 必须是1
if(i1!=1) return -7;

if(psucc!=NULL) *psucc=true;

strcpy(pself->pnode[ichannel].s_username,pstart);
strcpy(pself->pnode[ichannel].s_nickname,pend);
pself->pnode[ichannel].iattribute=ui2;//属性参数
pself->pnode[ichannel].imyshakecode=myshakecode;
//pself->iportchannel2=ichannel;
//pself->iportshakecode2=myshakecode;
//pself->iportyourshakecode2=yourshakecode;
return sprintf_s(sanswer,1000,"200 2 %u *%s*%s",pself->m_set.iattribute,pself->m_set.s_myname,pself->m_set.s_mynickname);


}
//当完成第一步握手 第二步对方返回后 这里执行的第三步 告诉对方是否连接成功完成 返回缓冲的长度
static const bool _stdcall Local_LoginEndStepFunc1(const __int32 ichannel, const unsigned __int16 myshakecode , const unsigned __int16 yourshakecode, const unsigned __int16 itxtsize , const char * pmsg )
{

TRACE(L"Login 3 function is called...\n");
int i1,i2;
unsigned int ui2=0;
char scmds[16];
memset(scmds,0,16);
char username[129];
memset(username,0,129);
char nickname[129];
memset(nickname,0,129);

char buffs[1600];
memset(buffs,0,1600);
memcpy( buffs,pmsg,itxtsize);
char * pstart;
pstart=strchr(buffs,'*');
if(pstart==NULL) return false;
*pstart='\0';
pstart++;
char * pend;
pend=strchr(pstart,'*');
if(pend==NULL) return false;
*pend='\0';
pend++;
if(*pstart=='\0' || *pend=='\0') return false;
//现在可以保证参数正确了

if(sscanf(pmsg,"%d %d %u",&i1,&i2,&ui2)!=3) return false;

if(i1!=200) return false;
if(i2!=2) return false;

//所有参数都正确 拷贝吧
pself->pnode[ichannel].iattribute=ui2;
strcpy(pself->pnode[ichannel].s_username,pstart);
strcpy(pself->pnode[ichannel].s_nickname,pend);

pself->pnode[ichannel].imyshakecode=myshakecode;


return true;
}
//当接收到对方发送的包的时候 执行的处理 参数是 我们通道的下标 我们的握手代码 是否通道里的子主动 包是文本包还是二进制包 TXT=TRUE ,最后是实际内容和长度
static const bool _stdcall Local_ProcNormalPacket1(const __int32 ichannel, const unsigned __int16 myshakecode , const bool bport , const bool btxt , const void * pbuff, const unsigned __int16 ibuffsize)
{
//请注意这个函数 您自己制作的协议 中的数据处理在这个函数中完成 如果有需要 可以分成 可靠传输数据处理 不可靠传输数据处理 分别执行
//但是 我们的示范 组网协议中 对可靠和不可靠传输采用相同的处理 因此只有一个处理函数
TRACE(L"packet found...\n");
if(ibuffsize<=4) return true;
char buffs[1600];
memcpy(buffs,pbuff,ibuffsize);
buffs[ibuffsize]='\0';

char * ptxt;


ptxt=buffs;
ptxt+=4;
if(strnicmp(buffs,"MSG ",4)==0)
{
//如果确实是我们规定的协议格式
pself->m_lock.Lock( );
pself->arr_channel.push_back(ichannel);
pself->arr_info.push_back(ptxt);
pself->m_lock.Unlock( );

//然后发送一个消息给主界面 WM_USER+1
::PostMessageW(pself->m_hWnd,(WM_USER+1),0,0);
//也许您认为 这里直接处理不好吗
//请注意 界面必须和后台数据分离
//这个函数不可以阻塞 虽然采用消息加拷贝会耗费系统资源 影响一点性能
//但是可以保证系统的健壮性 您在您自己的开发中也应该遵循这一点 非常重要
}
else
{
//不能识别的协议格式 直接放弃
//您扩展协议 可以将新的指令处理分支放在这里 如果指令分支大于10 建议您使用enum定义 把指令分支独立出来 使用switch进行处理

}

return true;
}

//当底层发现,需要中断一个连接的时候 调用本函数 参数是通道的下标 我们的握手代码 对方的握手代码 是否主动
static const void _stdcall Local_CloseChannelFunc1(const __int32 ichannel, const unsigned __int16 myshakecode , const unsigned __int16 yourshakecode, const bool bport)
{
pself->pnode[ichannel].bactive=false;
pself->mb_new=true;//通知定时器 有新的更新
TRACE(L"Close channel function is called , ichannel=%d\n",ichannel);
return;
}
//当一个指定的通道 某一个数据包被成功发送后 将调用这个函数 这样可以立即投递新的数据片 参数 ipos imyshakecode irev bsubport
static const void _stdcall Local_DataTransferFunc1(const __int32, const unsigned __int16 , const unsigned __int16, const bool )
{
//所有的数据包处理都在这个函数
//由于根据我们的协议 无论是可靠还是不可靠传输 都没有一一对应的回答 因此 我们这里简化了操作 只接收 不发送

return;
}

//当底层握手完毕 主动方发起的连接 成功完成所有步骤第一个是下标位置 前一个16位是我们的握手码 后一个是对方的握手码
const static __int32 _stdcall LoginPortPasvModeSuccess1(const __int32 ichannel, const unsigned __int16 myshakecode ,const unsigned __int16 yourshakecode)
{

TRACE(L"Login success fucntion is called , channel=%d\n",ichannel);
pself->pnode[ichannel].imyshakecode=myshakecode;
pself->pnode[ichannel].iyourshakecode=yourshakecode;
pself->pnode[ichannel].bactive=true;//关键
pself->mb_new=true;//通知定时器 有新的更新
return 0;
}


上面的几个函数是必须实现的,注意,我们使用的是全局静态函数,而与实际的数据结构脱钩,这是我们遵守的后台处理与前台界面分离的规则,而使用pself这个指针来调用具体的参数,这样,无论您如何修改界面,后台的处理始终是相同,并且不需要调整的.

我们的代码中,pself是全局指针,指向主对话框类,

static CNetFriendsDlg * pself; //这是为了让全局的会调函数 容易调用主对象内的资源

在程序最开始的执行处执行初始化

pself=&(*this);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
(c) 2011-2016 phoenixp2p.com