在网络通信程序中,一般都是启动服务端然后等待客户端主动过来连接,一个服务端多客户端模式,但最近工作中有个项目需要一个客户端连接到多个服务端,即一个客户端多服务端模式。所以客户端就需要考虑的多一点,需要连接到不同的服务端。
demo中两个类如下:
代码如下:
//DevConnect.h
#pragma once
#include <afxwin.h>
#include "Public.h"
#include "DevConnectThread.h"
class CDevConnect
{
public:
CDevConnect(void);
~CDevConnect(void);
static CDevConnect *Get(){ return &m_Connect; };
void Init(int nCount=10);
void Uninit();
BOOL AddConnect(char *szIP, int nPort); //添加需要连接的IP到列表
BOOL ImmediateConnect(char *szIP, int nPort); //快速连接,插入到列表最上面
void RemoveConnect(char *szIP, int nPort); //连接成功,移除该IP
BOOL FindConnect(char *szIP, int nPort);
BOOL GetConnect(_CONNECT_INFO &_ci);
BOOL SetConnectStatus(char *szIP, int nPort, char szStatus);
CDevConnectThread *GetThread();
V_CONNECT_INFO* GetAllOffLineDev(){ return &m_listConnect;}
private:
static CDevConnect m_Connect;
CRITICAL_SECTION m_crisec;
V_CONNECT_INFO m_listConnect;
V_CONNECT_THREAD m_listThread;
HANDLE m_hExitEvent;
HANDLE m_hThread;
int m_nCount;
void Lock() {::EnterCriticalSection(&m_crisec);}
void Unlock() {::LeaveCriticalSection(&m_crisec);}
static DWORD WINAPI procConnectThread(LPVOID lpContext);
static DWORD WINAPI procCheckOnlineThread(LPVOID lpContext);
};
//DevConnect.cpp
#include "StdAfx.h"
#include <algorithm>
#include "DevConnect.h"
#include "Ping.h"
CDevConnect CDevConnect::m_Connect;
DWORD WINAPI CDevConnect::procConnectThread(LPVOID lpContext)
{
CDevConnect *pThis = (CDevConnect*)lpContext;
if (pThis == NULL)
return 0;
_CONNECT_INFO _ci;
CDevConnectThread *pThread = NULL;
char szMsg[128] = {0};
while (1)
{
if (WaitForSingleObject(pThis->m_hExitEvent, 0) == WAIT_OBJECT_0)
break;
pThread = NULL;
memset(&_ci, 0, sizeof(_CONNECT_INFO));
if (pThis->GetConnect(_ci))
{
while (1)
{
if (WaitForSingleObject(pThis->m_hExitEvent, 0) == WAIT_OBJECT_0)
break;
pThread = pThis->GetThread();
if (pThread)
{
SP_ASSIGIN(szMsg, "空闲线程:%d, 准备连接IP:%s", pThread->GetHandleConnectThread(), _ci.szIP);
cout<<szMsg<<endl;
pThread->ConnectDev(_ci.szIP, _ci.nPort);
break;
}
Sleep(100);
}
}
Sleep(100);
}
return 0;
}
CDevConnect::CDevConnect(void)
{
m_nCount = 10;
InitializeCriticalSection(&m_crisec);
m_hExitEvent = NULL;
m_hThread = NULL;
}
CDevConnect::~CDevConnect(void)
{
::DeleteCriticalSection(&m_crisec);
}
void CDevConnect::Init(int nCount)
{
m_nCount = nCount;
char szMsg[128] = {0};
for (int i = 0; i < m_nCount; i++)
{
CDevConnectThread *pThread = new CDevConnectThread();
m_listThread.push_back(pThread);
pThread->Init();
SP_ASSIGIN(szMsg, "启动线程,Handle:%d", pThread->GetHandleConnectThread());
cout<<szMsg<<endl;
}
m_hExitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
m_hThread = ::CreateThread(NULL, 0, procConnectThread, this, 0, 0);
}
void CDevConnect::Uninit()
{
SetEvent(m_hExitEvent);
V_CONNECT_THREAD_ITE ite = m_listThread.begin();
while (ite != m_listThread.end())
{
CDevConnectThread *pThread = *ite;
if (pThread)
{
pThread->Uninit();
delete pThread;
}
ite = m_listThread.erase(ite);
}
if (m_hThread && WaitForSingleObject(m_hThread, 500) != WAIT_OBJECT_0)
{
::TerminateThread(m_hThread, 0);
CloseHandle(m_hThread);
m_hExitEvent = NULL;
}
}
BOOL CDevConnect::AddConnect(char *szIP, int nPort)
{
if (FindConnect(szIP, nPort))
return FALSE;
CDevConnectThread *pThread = GetThread();
if (pThread)
{
pThread->ConnectDev(szIP, nPort);
}
else
{
Lock();
_CONNECT_INFO _ci;
memset(&_ci, 0, sizeof(_CONNECT_INFO));
sprintf_s(_ci.szIP, "%s", szIP);
_ci.nPort = nPort;
_ci.tConnect = time(NULL);
_ci.nTimes = 0;
m_listConnect.push_back(_ci);
Unlock();
}
return TRUE;
}
BOOL CDevConnect::ImmediateConnect(char *szIP, int nPort)
{
if (FindConnect(szIP, nPort))
return FALSE;
CDevConnectThread *pThread = GetThread();
if (pThread)
{
pThread->ConnectDev(szIP, nPort);
}
else
{
Lock();
_CONNECT_INFO _ci;
memset(&_ci, 0, sizeof(_CONNECT_INFO));
sprintf_s(_ci.szIP, "%s", szIP);
_ci.nPort = nPort;
_ci.tConnect = time(NULL);
_ci.nTimes = 0;
m_listConnect.insert(m_listConnect.end(), _ci);
Unlock();
}
return TRUE;
}
void CDevConnect::RemoveConnect(char *szIP, int nPort)
{
_CONNECT_INFO _ci;
Lock();
V_CONNECT_INFO_ITE ite = m_listConnect.begin();
while (ite != m_listConnect.end())
{
memset(&_ci, 0, sizeof(_CONNECT_INFO));
_ci = *ite;
if (strcmp(_ci.szIP, szIP) == 0 &&
_ci.nPort == nPort)
{
m_listConnect.erase(ite);
break;
}
*ite++;
}
Unlock();
}
BOOL CDevConnect::FindConnect(char *szIP, int nPort)
{
BOOL bFind = FALSE;
_CONNECT_INFO _ci;
Lock();
V_CONNECT_INFO_ITE ite = m_listConnect.begin();
while (ite != m_listConnect.end())
{
memset(&_ci, 0, sizeof(_CONNECT_INFO));
_ci = *ite;
if (strcmp(_ci.szIP, szIP) == 0 &&
_ci.nPort == nPort)
{
bFind = TRUE;
break;
}
*ite++;
}
Unlock();
return FALSE;
}
BOOL CDevConnect::GetConnect(_CONNECT_INFO &_ci)
{
BOOL bFind = FALSE;
Lock();
V_CONNECT_INFO_ITE ite = m_listConnect.begin();
while (ite != m_listConnect.end())
{
memset(&_ci, 0, sizeof(_CONNECT_INFO));
_ci = *ite;
if (_ci.szStatus == 0 ||
(_ci.szStatus == 2 && difftime(time(NULL), _ci.tConnect) > 30))
{
m_listConnect.erase(ite);
bFind = TRUE;
break;
}
*ite++;
}
if (bFind)
{
_ci.tConnect = time(NULL);
_ci.szStatus = 1;
m_listConnect.push_back(_ci);
}
Unlock();
return bFind;
}
CDevConnectThread *CDevConnect::GetThread()
{
CDevConnectThread *p = NULL, *pRet=NULL;
V_CONNECT_THREAD_ITE ite = m_listThread.begin();
while (ite != m_listThread.end())
{
p = *ite;
if (p && p->IsFree())
{
pRet = p;
break;
}
*ite++;
}
return pRet;
}
BOOL CDevConnect::SetConnectStatus(char *szIP, int nPort, char szStatus)
{
BOOL bFind = FALSE;
_CONNECT_INFO _ci;
Lock();
V_CONNECT_INFO_ITE ite = m_listConnect.begin();
while (ite != m_listConnect.end())
{
memset(&_ci, 0, sizeof(_CONNECT_INFO));
_ci = *ite;
if (strcmp(_ci.szIP, szIP) == 0 &&
_ci.nPort == nPort)
{
_ci.tConnect = time(NULL);
_ci.szStatus = szStatus;
*ite = _ci;
bFind = TRUE;
break;
}
*ite++;
}
if (!bFind && (szStatus == 0 || szStatus == 2))
{
_CONNECT_INFO _ci;
memset(&_ci, 0, sizeof(_CONNECT_INFO));
sprintf_s(_ci.szIP, "%s", szIP);
_ci.nPort = nPort;
_ci.tConnect = time(NULL);
_ci.nTimes = 0;
m_listConnect.push_back(_ci);
}
Unlock();
return bFind;
}
//DevConnectThread.h
#pragma once
#include <afxwin.h>
#include <vector>
#include <iostream>
using namespace std;
class CDevConnectThread
{
public:
CDevConnectThread(void);
~CDevConnectThread(void);
void Init(); //创建线程
void Uninit(); //结束线程
BOOL IsFree();
void FreeThread();
BOOL ConnectDev(char *szIP, int nPort);
LONG GetHandleConnectThread(){ return HandleToLong(m_hConnectThread); }
private:
char m_szIP[24];
int m_nPort;
BOOL m_bFree;
HANDLE m_hExitEvent; //是否退出线程的信号量
HANDLE m_hNotifyEvent; //线程是否被通知的信号量
HANDLE m_hConnectThread; //线程句柄
static DWORD WINAPI procConnectThread(LPVOID lpContext);
void DoJob();
};
typedef vector<CDevConnectThread*> V_CONNECT_THREAD;
typedef V_CONNECT_THREAD::iterator V_CONNECT_THREAD_ITE;
//DevConnectThread.cpp
#include "StdAfx.h"
#include "DevConnect.h"
#include "DevConnectThread.h"
#include "Ping.h"
DWORD WINAPI CDevConnectThread::procConnectThread(LPVOID lpContext)
{
CDevConnectThread *pThis = (CDevConnectThread*)lpContext;
if (pThis == NULL)
return 0;
HANDLE HandleArray[2];
HandleArray[0] = pThis->m_hNotifyEvent;
HandleArray[1] = pThis->m_hExitEvent;
while (1)
{
DWORD ret = ::WaitForMultipleObjects(2, HandleArray, false, INFINITE);
if(ret == WAIT_OBJECT_0)
{
pThis->DoJob();
}
else if (ret == WAIT_OBJECT_0 + 1)
{
break;//退出线程
}
Sleep(100);
}
return 0;
}
CDevConnectThread::CDevConnectThread(void)
{
m_bFree = TRUE;
m_hExitEvent = NULL;
m_hNotifyEvent = NULL;
m_hConnectThread = NULL;
memset(m_szIP, 0, sizeof(m_szIP));
m_nPort = 6000;
}
CDevConnectThread::~CDevConnectThread(void)
{
}
void CDevConnectThread::Init()
{
m_hExitEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
m_hNotifyEvent = CreateEvent(0, FALSE, FALSE, NULL);
m_hConnectThread = ::CreateThread(NULL, 0, procConnectThread, this, 0, 0);
}
void CDevConnectThread::Uninit()
{
SetEvent(m_hExitEvent);
if (m_hConnectThread && WaitForSingleObject(m_hConnectThread, 200) != WAIT_OBJECT_0)
{
::TerminateThread(m_hConnectThread, 0);
CloseHandle(m_hConnectThread);
m_hConnectThread = NULL;
}
if (m_hNotifyEvent && WaitForSingleObject(m_hNotifyEvent, 200) != WAIT_OBJECT_0)
{
::TerminateThread(m_hNotifyEvent, 0);
CloseHandle(m_hNotifyEvent);
m_hNotifyEvent = NULL;
}
}
BOOL CDevConnectThread::IsFree()
{
if (m_bFree)
{
m_bFree = FALSE;
return TRUE;
}
return FALSE;
}
void CDevConnectThread::FreeThread()
{
m_bFree = TRUE;
}
BOOL CDevConnectThread::ConnectDev(char *szIP, int nPort)
{
memset(m_szIP, 0, sizeof(m_szIP));
if (szIP == NULL)
return FALSE;
m_nPort = nPort;
sprintf_s(m_szIP, "%s", szIP);
SetEvent(m_hNotifyEvent);
return TRUE;
}
void CDevConnectThread::DoJob()
{
char szMsg[128] = {0};
if (CPing::Get()->Ping(m_szIP))
{
//如果ping通,可以在此做TCP/UDP连接
//...
SP_ASSIGIN(szMsg, "线程:%d, 连接成功, IP:%s", m_hConnectThread, m_szIP);
cout<<szMsg<<endl;
CDevConnect::Get()->RemoveConnect(m_szIP, m_nPort);
}
else
{
SP_ASSIGIN(szMsg, "线程:%d, 连接失败, IP:%s", m_hConnectThread, m_szIP);
cout<<szMsg<<endl;
}
FreeThread();
}
运行截图:
欢迎加入我们的qq讨论群:184821652