1.FeiQ项目
1.1 登录的时候给当前所在局域网内所有IP发送一个广播
- 1.发送广播是应该在主对话框的初始化时进行的;
- 2.发送的数据是上线请求数据;
- 3.IP 是本机的 IP ,可以通过 Net 的 GetLocalIPAddr 函数获得;
- 4.通过中介者调用 SendData 来进行发送数据;
BOOL CFeiQProjDlg::OnInitDialog()
{
... ...
STRU_ONLINE_RQ soRQ;
soRQ.pack_type = PROTOCL_ONLINE_RQ;
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = theApp.m_p_mediator->p_net->GetLocalIPAddr();
strcpy_s(soRQ.sz_user_name, NAME_SIZE, inet_ntoa(addr.sin_addr));
theApp.m_p_mediator->SendData(INADDR_BROADCAST, (const char*)&soRQ, sizeof(soRQ));
return TRUE;
}
1.2 我们在创建主对话框时发送了一条广播,那么其他人接受到这条广播数据之后应该如何进行处理,我们在中介者的 DealData 函数中给出
- 1.接受到数据包后, DealData 函数首先将数据包的包头取出来,判断是哪种数据类型,在进行进一步的判断;
- 2.若是上线请求数据包,我们给主窗口发送一个消息,这个消息用来给主对话框添加IP,之后我们发送一个确认上线的数据包;
bool CUDPMediator::DealData(ULONG uIP, char* pszSendBuffer, int nSendLen)
{
PackType* p_type = (PackType*)pszSendBuffer;
switch (*p_type)
{
case PROTOCL_ONLINE_RQ:
{
STRU_ONLINE_RQ* soRQ = (STRU_ONLINE_RQ*)pszSendBuffer;
theApp.m_pMainWnd->SendMessage(UM_ONLINE, 0, (LPARAM)(soRQ->sz_user_name));
STRU_ONLINE_RS soRS;
soRS.pack_type = PROTOCL_ONLINE_RS;
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = p_net->GetLocalIPAddr();
strcpy_s(soRS.sz_user_name, NAME_SIZE, inet_ntoa(addr.sin_addr));
this->SendData(inet_addr(soRQ->sz_user_name), (const char*)&soRS, sizeof(soRS));
}
break;
}
return true;
}
- 3.在 PackDef.h 中定义一个消息用来映射将IP写到主对话框上的函数,定义的宏为 UM_ONLINE_RQ ;
- 4.在主对话框类中定义一个自定义消息处理函数,在该函数中调用 m_lb_IPAddr 对象的 InsertIP 函数;
BEGIN_MESSAGE_MAP(CFeiQProjDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(UM_ONLINE_RQ, &CFeiQProjDlg::OnOnLineRQ)
END_MESSAGE_MAP()
LRESULT CFeiQProjDlg::OnOnLineRQ(WPARAM wParam, LPARAM lParam)
{
char* psz_user_name = (char*)lParam;
m_lb_IPAddr.InsertIP(psz_user_name);
return 0;
}
1.3 在中介者的上线回复包中给主窗口发送一个自定义消息,用来将接收到的回复包中的IP插入到主对话框中
bool CUDPMediator::DealData(ULONG uIP, char* pszSendBuffer, int nSendLen)
{
PackType* p_type = (PackType*)pszSendBuffer;
switch (*p_type)
{
... ...
case PROTOCL_ONLINE_RS:
{
STRU_ONLINE_RS* soRS = (STRU_ONLINE_RS*)pszSendBuffer;
theApp.m_pMainWnd->SendMessage(UM_ONLINE_RS, 0, (LPARAM)(soRS->sz_user_name));
}
break;
}
return true;
}
- 1.再在主对话框中添加一个与 OnOnLineRQ 函数类似的函数,用来处理 UM_ONLINE_RS 消息;
BEGIN_MESSAGE_MAP(CFeiQProjDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_MESSAGE(UM_ONLINE_RQ, &CFeiQProjDlg::OnOnLineRQ)
ON_MESSAGE(UM_ONLINE_RS, &CFeiQProjDlg::OnOnLineRS)
END_MESSAGE_MAP()
LRESULT CFeiQProjDlg::OnOnLineRS(WPARAM wParam, LPARAM lParam)
{
char* psz_user_name = (char*)lParam;
m_lb_IPAddr.InsertIP(psz_user_name);
return 0;
}
1.4 关闭主对话框时也需给当前局域网中所有的IP发送一个广播
- 1.与初始化对话框的发送广播基本一样,不同之处在于发送的数据包的类型不同;
- 2.给主对话框类添加一个 WM_CLOSE 消息,在该消息处理函数中发送广播;
void CFeiQProjDlg::OnClose()
{
STRU_OFFLINE_RQ soRQ;
soRQ.pack_type = PROTOCL_OFFLINE_RQ;
sockaddr_in addr;
addr.sin_addr.S_un.S_addr = theApp.m_p_mediator->p_net->GetLocalIPAddr();
strcpy_s(soRQ.sz_user_name, NAME_SIZE, inet_ntoa(addr.sin_addr));
theApp.m_p_mediator->SendData(INADDR_BROADCAST, (const char*)&soRQ, sizeof(soRQ));
CDialogEx::OnClose();
}
1.5 当别的客户端下线的时候,我们会收到一个 STRU_OFFLINE_RQ 消息,在中介者中进行处理
bool CUDPMediator::DealData(ULONG uIP, char* pszSendBuffer, int nSendLen)
{
PackType* p_type = (PackType*)pszSendBuffer;
switch (*p_type)
{
... ...
case PROTOCL_OFFLINE_RQ:
{
STRU_OFFLINE_RQ* soRQ = (STRU_OFFLINE_RQ*)pszSendBuffer;
theApp.m_pMainWnd->SendMessage(UM_OFFLINE_RQ, 0, (LPARAM)soRQ->sz_user_name);
}
break;
}
return true;
}
- 1.再在主对话框中添加一个消息处理函数: OnOffLineRQ ;
- 2.首先查找 listbox 控件中的IP,存在的话就删除;
- 3.再在map中查找,有的话就删除map中的值;
LRESULT CFeiQProjDlg::OnOffLineRQ(WPARAM wParam, LPARAM lParam)
{
char* psz_user_name = (char*)lParam;
for(int i=0; i<m_lb_IPAddr.GetCount(); i++)
{
CString strIP;
m_lb_IPAddr.GetText(i, strIP);
if(strIP == psz_user_name)
{
m_lb_IPAddr.DeleteString(i);
break;
}
}
if(m_lb_IPAddr.m_mp_sayDlg.count(psz_user_name) == 1)
{
map<CString, CSayDlg*>::iterator ite = m_lb_IPAddr.m_mp_sayDlg.find(psz_user_name);
delete ite->second;
m_lb_IPAddr.m_mp_sayDlg.erase(ite);
}
return 0;
}