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)
{
}
}
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;
hostent* p_host = ::gethostbyname(sz_name);
if(p_host == 0)
return -1;
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()
{
... ...
INet* p = new CUDPNet;
if(p->OpenNet() == false)
{
if (pShellManager != NULL)
{
delete pShellManager;
}
return FALSE;
}
sockaddr_in in;
in.sin_addr.S_un.S_addr = p->GetLocalIPAddr();
TRACE("%s\n", inet_ntoa(in.sin_addr));
... ...
}
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 类
#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:
{
}
break;
case PROTOCL_OFFLINE_RQ:
{
STRU_OFFLINE_RQ* soRQ = (STRU_OFFLINE_RQ*)pszSendBuffer;
}
break;
case PROTOCL_OFFLINE_RS:
{
}
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()
{
... ...
if(false == m_p_mediator->InitMediator())
{
if (pShellManager != NULL)
{
delete pShellManager;
}
return FALSE;
}
... ...
}