操作系统与网络 2019-3-26

1.FeiQ项目

1.1 登录的时候给当前所在局域网内所有IP发送一个广播

  • 1.发送广播是应该在主对话框的初始化时进行的;
  • 2.发送的数据是上线请求数据;
  • 3.IP 是本机的 IP ,可以通过 Net 的 GetLocalIPAddr 函数获得;
  • 4.通过中介者调用 SendData 来进行发送数据;
BOOL CFeiQProjDlg::OnInitDialog()
{
	... ...

	// =====================3-26发送广播========================
	// 定义一个登陆的数据包
	STRU_ONLINE_RQ soRQ;
	soRQ.pack_type = PROTOCL_ONLINE_RQ;
	// 把IP装到包里
	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));
	// =====================3-26发送广播========================

	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;
			// 1.把对方发来的IP插入到本地窗口上(通过给主对话框发送消息来进行)
			theApp.m_pMainWnd->SendMessage(UM_ONLINE, 0, (LPARAM)(soRQ->sz_user_name));
			// 2.给对方发送一个上线回复包
			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;
	// 把IP装到包里
	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;
	//bool b_flag = false;
	// 先删除列表控件中的字符串
	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);
			//b_flag = true;
			break;
		}
	}

	if(m_lb_IPAddr.m_mp_sayDlg.count(psz_user_name) == 1)
	{
		// 删除map中的节点
		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;
}

猜你喜欢

转载自blog.csdn.net/weixin_42896619/article/details/88942100
今日推荐