上位机多线程处理多台设备的连接

最近工作中有个这样的场景,C++上位机需要通过TCP连接很多台设备,而在连接之前需要知道哪些设备在线,哪些不在线。

所以很自然想到了开启多个线程,ping目标ip。这样可以快速的遍历完所有的IP。

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();
}

运行截图:

扫描二维码关注公众号,回复: 10186534 查看本文章

欢迎加入我们的qq讨论群:184821652

发布了27 篇原创文章 · 获赞 9 · 访问量 4890

猜你喜欢

转载自blog.csdn.net/weixin_41761608/article/details/94010721