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

1.继续FeiQ项目

1.1 继续 UDPNet 类,完成 CloseNet 函数

  • 1.将退出线程变量置为 false ;
  • 2.关闭套接字;
  • 3.关闭线程;
  • 4.卸载库;
void CUDPNet::CloseNet()
{
	m_b_qiut_thread = false;

	// 关闭套接字
	::closesocket(m_socket);
	m_socket = 0;

	// 关闭线程
	if(::WaitForSingleObject(m_h_thread, 10) == WAIT_TIMEOUT)
	{
		::TerminateThread(m_h_thread, -1);
		::CloseHandle(m_h_thread);
		m_h_thread = 0;
	}

	// 卸载库
	WSACleanup();
}

1.2 完成 UDPNet 类的 SendData 函数

  • 1.先判断是否接收到数据,没接收到返回 false ;
  • 2.使用当前套接字发送数据;
bool CUDPNet::SendData(ULONG uIP, const char* pszSendBuffer, int nSendLen)
{
	if(pszSendBuffer == NULL || nSendLen <= 0)
		return false;

	// 发送信息
	sockaddr_in addr_to;
	addr_to.sin_addr.S_un.S_addr = uIP;
	addr_to.sin_family = AF_INET;
	addr_to.sin_port = htons(PORT);
	int n_send_len = ::sendto(m_socket, pszSendBuffer, nSendLen, 0, (const sockaddr*)&addr_to, sizeof(addr_to));
	if(n_send_len <= 0)
	{
		return false;
	}

	return true;
}

1.3 UDPNet 中的线程处理函数,作用是接收数据

  • 1.使用 recvfrom 函数来接收数据;
  • 2.每次接收之前先清空一下存放数据的空间
unsigned int _stdcall CUDPNet::ThreadProc(LPVOID lPvoid)
{
	// 作用是用来接受数据
	CUDPNet* p_this = (CUDPNet*) lPvoid;
	char sz_buffer[RECV_BUFFER] = {0};

	sockaddr_in addr_from;
	int n_addr_len = sizeof(addr_from);
	while (p_this->m_b_qiut_thread)
	{
		::ZeroMemory(sz_buffer, RECV_BUFFER);
		int n_recv_len = ::recvfrom(p_this->m_socket, sz_buffer, RECV_BUFFER, 0, (sockaddr*)&addr_from, &n_addr_len);
		if(n_recv_len >= 0)
		{
			// 交给中继者去处理
			// TODO:
		}
	}

	return 0;
}

1.4 给 Net.h 添加一个获取本机名和本机IP的函数

  • 1.首先获取主机名: gethostname ;
  • 2.获取IP列表: gethostbyname ;
ULONG GetLocalIPAddr()
	{
		char sz_name[100] = {0};
		// 获取主机名
		if(::gethostname(sz_name, 100) != 0)			// 该函数需要在加载库之前
			return -1;

		// 获取IP列表
		hostent* p_host = ::gethostbyname(sz_name);
		if(p_host == 0)
			return -1;

		// 取得IP地址
		char* nIP = p_host->h_addr_list[0];
		sockaddr_in in;
		::memcpy(&(in.sin_addr.S_un.S_addr), nIP, p_host->h_length);
		return in.sin_addr.S_un.S_addr;
	}

1.5 在 App 类中进行调用

  • 1.在打开网络之后定义一个 sockaddr_in 类型的变量用来存放 IP ;
BOOL CFeiQProjApp::InitInstance()
{
	... ...

	// ==========================3-22 打开网络==========================
	INet* p = new CUDPNet;
	if(p->OpenNet() == false)
	{
		// 删除上面创建的 shell 管理器。
		if (pShellManager != NULL)
		{
			delete pShellManager;
		}
		return FALSE;
	}
	// ==========================3-22 打开网络==========================

	//======================3-25 打印本机IP==========================
	sockaddr_in in;
	in.sin_addr.S_un.S_addr = p->GetLocalIPAddr();
	TRACE("%s\n", inet_ntoa(in.sin_addr));
	//======================3-25 打印本机IP==========================

	... ...
}

1.6 完成中介者的基类 IMediator

  • 1.需要定义一个 INet 类的指针对象,用来进行网络方面的初始化等操作;
  • 2.在构造函数中赋值为零;
  • 3.虚析构、虚初始化函数、虚卸载函数、虚发送数据函数(参数与Net中的SendData函数相同)、虚处理数据函数(参数与SendData大致类似,不同的就是数据是可以进行修改的);
#pragma once
#include "Net.h"

class IMediator
{
public:
	INet* p_net;

public:
	IMediator(){p_net = 0;};
	virtual ~IMediator(){};

public:
	virtual bool InitMediator()=0;
	virtual void ClearupMediator()=0;
	virtual bool SendData(ULONG uIP, const char* pszSendBuffer, int nSendLen)=0;
	virtual bool DealData(ULONG uIP, char* pszSendBuffer, int nSendLen)=0;
};

1.7 完成 UDPMediator 类

  • 1.继承自 IMediator 类;
#pragma once
#include "Mediator.h"

class CUDPMediator:public IMediator
{
public:
	CUDPMediator();
	virtual ~CUDPMediator();

public:
	virtual bool InitMediator();
	virtual void ClearupMediator();
	virtual bool SendData(ULONG uIP, const char* pszSendBuffer, int nSendLen);
	virtual bool DealData(ULONG uIP, char* pszSendBuffer, int nSendLen);
};
  • 2.在构造函数中 new 一个CUDONet对象,用来进行网络的初始化、关闭等操作;
  • 3.在析构函数中删除创建的对象;
  • 4.在初始化中介者函数中打开网络,在卸载中介者函数中关闭网络,在发送数据函数中使用网络发送数据;
  • 5.在处理数据函数中,先获得数据包的包头,用来确定数据包是什么类型的数据包(在PackDef.h中我们定义了四种数据包,包括上下线等),并通过包头来将数据包转成相应的类型;
#include "stdafx.h"
#include "UDPMediator.h"
#include "UDPNet.h"
#include "../PackDef/PackDef.h"

CUDPMediator::CUDPMediator()
{
	p_net = new CUDPNet;
}

CUDPMediator::~CUDPMediator()
{
	delete(p_net);
	p_net = 0;
}


bool CUDPMediator::InitMediator()
{
	if(p_net->OpenNet() == false)
		return false;
	return true;
}

void CUDPMediator::ClearupMediator()
{
	p_net->CloseNet();
}

bool CUDPMediator::SendData(ULONG uIP, const char* pszSendBuffer, int nSendLen)
{
	if(p_net->SendData(uIP, pszSendBuffer, nSendLen) == false)
		return false;
	return true;
}

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;
		}
		break;

	case PROTOCL_ONLINE_RS:
		{
			//STRU_ONLINE_RS* soRS = (STRU_ONLINE_RS*)pszSendBuffer;
		}
		break;

	case PROTOCL_OFFLINE_RQ:
		{
			STRU_OFFLINE_RQ* soRQ = (STRU_OFFLINE_RQ*)pszSendBuffer;
		}
		break;

	case PROTOCL_OFFLINE_RS:
		{
			//STRU_OFFLINE_RS* soRQ = (STRU_OFFLINE_RS*)pszSendBuffer;
		}
		break;
	}

	return true;
}

1.8 修改 UDPNet 类

  • 1.给 UDPNet 类定义一个中介者对象;
  • 2.把 UDPNet 的构造函数更改为带参构造,参数是 Mediator 中介者指针对象;
  • 3.在线程处理函数中使用中介者对象调用处理数据的函数;
CUDPNet::CUDPNet(IMediator* p_mediator)
{
	m_p_mediator = p_mediator;
	m_socket = 0;
	m_b_qiut_thread = true;
	m_h_thread = 0;
}

unsigned int _stdcall CUDPNet::ThreadProc(LPVOID lPvoid)
{
	// 作用是用来接受数据
	CUDPNet* p_this = (CUDPNet*) lPvoid;
	char sz_buffer[RECV_BUFFER] = {0};

	sockaddr_in addr_from;
	int n_addr_len = sizeof(addr_from);
	while (p_this->m_b_qiut_thread)
	{
		::ZeroMemory(sz_buffer, RECV_BUFFER);
		int n_recv_len = ::recvfrom(p_this->m_socket, sz_buffer, RECV_BUFFER, 0, (sockaddr*)&addr_from, &n_addr_len);
		if(n_recv_len >= 0)
		{
			// ===============================给中继者去处理===============================
			p_this->m_p_mediator->DealData(addr_from.sin_addr.S_un.S_addr, sz_buffer, n_recv_len);
			// ===============================给中继者去处理===============================
		}
	}

	return 0;
}
  • 4.修改 CUDPMediator 类的构造函数,因为我们修改了 UDPNet 的构造函数,因此我们需要在 new 的时候传递参数进去;
CUDPMediator::CUDPMediator()
{
	p_net = new CUDPNet(this);
}
  • 5.在 App 类中初始化一个中介者对象,不再单单初始化一个网络对象;先定义一个 IMediator 对象,在构造函数中 new 一个UDPMediator,再在 InitInstance 函数中调用初始化函数;
CFeiQProjApp::CFeiQProjApp()
{
	... ...

	// ==========================3-22 打开网络==========================
	//INet* p = new CUDPNet;
	//if(p->OpenNet() == false)
	//{
	//	// 删除上面创建的 shell 管理器。
	//	if (pShellManager != NULL)
	//	{
	//		delete pShellManager;
	//	}
	//	return FALSE;
	//}
	// ==========================3-22 打开网络==========================

	// ==========================3-25 打开中介者==========================
	if(false == m_p_mediator->InitMediator())
	{
		// 删除上面创建的 shell 管理器。
		if (pShellManager != NULL)
		{
			delete pShellManager;
		}
		return FALSE;
	}
	// ==========================3-25 打开中介者==========================

	//======================3-25 打印本机IP==========================
	//sockaddr_in in;
	//in.sin_addr.S_un.S_addr = p->GetLocalIPAddr();
	//TRACE("%s\n", inet_ntoa(in.sin_addr));
	//======================3-25 打印本机IP==========================

	... ...
}

猜你喜欢

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