头文件:
#ifndef __MANAGE_NET__
#define __MANAGE_NET__
#include <vector>
#include <string>
#include <process.h>
#include <winsock2.h>
#include <functional>
using namespace std;
class BroadcastClient
{
public:
BroadcastClient();
~BroadcastClient();
public:
static BroadcastClient* m_Instance;
static BroadcastClient* GetInstance()
{
if (!m_Instance){
m_Instance = new BroadcastClient;
}
return m_Instance;
}
static void ReleaseInstance()
{
if (m_Instance){
delete m_Instance;
m_Instance = NULL;
}
}
bool SetFunc(const std::function<void(const char*, long)>& func);
bool Init(long nPort);
bool Write(unsigned char* pData, long nSize);
void Uninit();
private:
bool Connect(long nPort);
void DisConnect();
long Read(unsigned char* pData, long nSize);
static unsigned int __stdcall Process(void* args);
private:
std::function<void(const char*, long)> m_pFunc;
private:
HANDLE m_threadRecv;
HANDLE m_threadEvent;
private:
long m_nPort;
private:
SOCKET sClient;
private:
SOCKADDR_IN m_clientAddr;
};
#endif
源文件:
#include "BroadcastClient.h"
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
BroadcastClient* BroadcastClient::m_Instance = NULL;
BroadcastClient::BroadcastClient()
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
m_threadRecv = INVALID_HANDLE_VALUE;
m_threadEvent = INVALID_HANDLE_VALUE;
}
BroadcastClient::~BroadcastClient()
{
Uninit();
WSACleanup();
}
bool BroadcastClient::SetFunc(const std::function<void(const char*, long)>& pFunc)
{
if (pFunc){
m_pFunc = pFunc;
return true;
}
return false;
}
bool BroadcastClient::Connect(long nPort)
{
sClient = socket(AF_INET, SOCK_DGRAM, 0);
if (sClient == INVALID_SOCKET){
return false;
}
struct sockaddr_in seraddr;
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(nPort);
seraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//IP地址
if (::bind(sClient, (SOCKADDR*)&seraddr, sizeof(seraddr)) != 0){
DWORD dwErr = GetLastError();
return false;
}
int nTimeout = 1000;//
setsockopt(sClient, SOL_SOCKET, SO_SNDTIMEO, (char *)&nTimeout, sizeof(int));
setsockopt(sClient, SOL_SOCKET, SO_RCVTIMEO, (char *)&nTimeout, sizeof(int));
return true;
}
bool BroadcastClient::Init(long nPort)
{
bool bRet = Connect(nPort);
if (bRet){
m_nPort = nPort;
m_threadEvent = CreateEvent(NULL, true, false, L"");
m_threadRecv = (HANDLE)_beginthreadex(NULL, 0, Process, this, 0, NULL);
return true;
}
return false;
}
long BroadcastClient::Read(unsigned char* pData, long nSize)
{
if(sClient != INVALID_SOCKET){
int addrLen = sizeof(m_clientAddr);
return recvfrom(sClient, (char*)pData, nSize, 0, (SOCKADDR*)&m_clientAddr, &addrLen);
}
return 0;
}
bool BroadcastClient::Write(unsigned char* pData, long nSize)
{
int addrLen = sizeof(m_clientAddr);
long nLen = sendto(sClient, (char*)pData, nSize, 0, (SOCKADDR*)&m_clientAddr, addrLen);
if(nLen == SOCKET_ERROR){
return false;
}
return true;
}
void BroadcastClient::Uninit()
{
if (m_threadRecv != INVALID_HANDLE_VALUE && m_threadEvent != INVALID_HANDLE_VALUE){
SetEvent(m_threadEvent);
WaitForSingleObject(m_threadRecv, INFINITE);
CloseHandle(m_threadRecv);
CloseHandle(m_threadEvent);
m_threadRecv = INVALID_HANDLE_VALUE;
m_threadEvent = INVALID_HANDLE_VALUE;
}
DisConnect();
}
void BroadcastClient::DisConnect()
{
closesocket(sClient);
sClient = INVALID_SOCKET;
}
unsigned int BroadcastClient::Process(void* args)
{
BroadcastClient* pThis = (BroadcastClient*)args;
while (true){
if (WaitForSingleObject(pThis->m_threadEvent, 10) == WAIT_OBJECT_0){
break;
}
char cData[2048] = { 0 };
long nRet = pThis->Read((unsigned char*)cData, 2048);
if (nRet > 0){
if (pThis->m_pFunc){
pThis->m_pFunc(cData, nRet);
}
}
else {
if (nRet == 0){//不能在这里调用Uninit。因为会发生死锁
pThis->DisConnect();
pThis->Connect(pThis->m_nPort);
}
else if (nRet == SOCKET_ERROR){
if (WSAGetLastError() != WSAETIMEDOUT){
pThis->DisConnect();
pThis->Connect(pThis->m_nPort);
}
}
}
}
return 0;
}
调用:
BroadcastClient::GetInstance()->SetFunc(&ManageNetCB::ProcessNet);
BroadcastClient::GetInstance()->Init(8001);
char cData[2048] = {0};
sprintf(cData, "cmd=ReportStudentName_req&data=%s\n", UNICODE_TO_ANSI(wcData).c_str());
BroadcastClient::GetInstance()->Write((unsigned char*)cData, strlen(cData));