注:核心内容使用了此处的实现,我只是做了下小封装

开一个线程专门来刷ip的延时,可以使用在类似于联机大厅计算到各IP的延迟。有一个需求需要计算N个ip的延迟,所以才知道了有ICMP这个东西,学习了。

简易的线程封装,支持基于message的同步

#ifndef _INC_MACROHELPER_
#define _INC_MACROHELPER_
//////////////////////////////////////////////////////////////////////////
#define READWRITE_PROPERTY(VAR, NAME, TYPE)		protected:TYPE VAR;READWRITE_INTERFACE(VAR, NAME, TYPE);
#define READWRITE_INTERFACE(VAR, NAME, TYPE)	READ_INTERFACE(VAR, NAME, TYPE)WRITE_INTERFACE(VAR, NAME, TYPE)
#define READ_INTERFACE(VAR, NAME, TYPE)			public:TYPE Get##NAME(){return VAR;}
#define WRITE_INTERFACE(VAR, NAME, TYPE)		public:void Set##NAME(TYPE _var){VAR = _var;}
//////////////////////////////////////////////////////////////////////////
#endif
#ifndef _INC_THREADRUNNER_
#define _INC_THREADRUNNER_
//////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <process.h>
#include <exception>
#include "MacroHelper.h"
//////////////////////////////////////////////////////////////////////////
typedef unsigned char ThreadNumber;
//////////////////////////////////////////////////////////////////////////
#define RUNTHREAD_PREPARED_EVENT	"RunThread prepared event"
//////////////////////////////////////////////////////////////////////////
class ThreadRunner
{
public:
	enum THREAD_STATE
	{
		TS_STOP,
		TS_RUN,
		TS_PAUSE
	};
 
	enum THREAD_RESULT
	{
		TR_SETEVENTFAILED = 0xFFFF0000
	};
 
public:
	ThreadRunner()
	{
		m_eThreadState = TS_STOP;
		m_hPreparedEvt = NULL;
		m_hThread = NULL;
		m_uThreadID = 0;
		m_dwRunSleepTime = 1;
 
		m_uTerminate = m_uPause = 0;
		m_dwLastRunCostTime = 0;
 
		m_hPreparedEvt = CreateEvent(NULL,
			FALSE,//	Autoreset
			FALSE,
			RUNTHREAD_PREPARED_EVENT);
 
		if(m_hPreparedEvt == NULL)
		{
			throw std::exception("Can't create the thread event in [ThreadRunner]");
		}
	}
	virtual ~ThreadRunner()
	{
		Stop();
 
		CloseHandle(m_hPreparedEvt);
 
		while(1)
		{
			if(GetThreadState() == TS_STOP)
			{
				break;
			}
		}
	}
 
public:
	virtual bool Run()
	{
		if(GetThreadState() != TS_STOP)
		{
			return false;
		}
 
		m_hThread = (HANDLE)_beginthreadex(NULL,
			0,
			&ThreadRunner::ThreadProc,
			this,
			0,
			&m_uThreadID);
 
		if(NULL == m_hThread)
		{
			return false;
		}
 
		return true;
	}
	virtual unsigned int Thread_DoWork()
	{
		return 0;
	}
	virtual unsigned int Thread_Initialize()
	{
		return 0;
	}
	virtual unsigned int Thread_ProcessMessage(const MSG* _pMsg)
	{
		return 0;
	}
 
public:
	void Stop()
	{
		m_uTerminate = 1;
		//m_eThreadState = TS_STOP;
	}
	void Pause()
	{
		m_uPause = 1;
		//m_eThreadState = TS_PAUSE;
	}
	void Resume()
	{
		m_uPause = 0;
		//m_eThreadState = TS_RUN;
	}
 
	void PostRunnerMessage(const MSG* _pMsg)
	{
		if(GetThreadState() == TS_RUN)
		{
			PostThreadMessage(GetThreadID(), _pMsg->message, _pMsg->wParam, _pMsg->lParam);
		}
	}
 
public:
	//	setter and getter
	READWRITE_INTERFACE(m_hThread, ThreadHandle, HANDLE);
	READWRITE_INTERFACE(m_uThreadID, ThreadID, unsigned int);
	READWRITE_INTERFACE(m_dwRunSleepTime, RunSleepTime, DWORD);
	READ_INTERFACE(m_eThreadState, ThreadState, THREAD_STATE);
	READ_INTERFACE(m_hPreparedEvt, PreparedEvt, HANDLE);
	READ_INTERFACE(m_dwLastRunCostTime, LastRunCostTime, DWORD);
 
private:
	static unsigned int __stdcall ThreadProc(void* _pParam)
	{
		ThreadRunner* pThread = (ThreadRunner*)_pParam;
		unsigned int uRet = 0;
 
		//	Create the message loop
		MSG msg;
		PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
		ZeroMemory(&msg, sizeof(MSG));
 
		if(!SetEvent(pThread->m_hPreparedEvt))
		{
			uRet = TR_SETEVENTFAILED;
		}
 
		//	Initialize
		uRet = pThread->Thread_Initialize();
		DWORD dwCurTick = GetTickCount();
 
		//	a runloop
		while(0 == uRet)
		{
			//	Process thread message
			if(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				uRet = pThread->Thread_ProcessMessage(&msg);
			}
			if(0 != uRet)
			{
				break;
			}
 
			//	Stop or pause this thread
			if(pThread->m_uPause)
			{
				pThread->m_eThreadState = TS_PAUSE;
				SleepEx(pThread->GetRunSleepTime(), TRUE);
				continue;
			}
			if(pThread->m_uTerminate)
			{
				break;
			}
 
			//	Do thread work
			pThread->m_eThreadState = TS_RUN;
			dwCurTick = GetTickCount();
 
			uRet = pThread->Thread_DoWork();
			if(0 != uRet)
			{
				break;
			}
 
			pThread->m_dwLastRunCostTime = GetTickCount() - dwCurTick;
 
			//	Into sleep
			SleepEx(pThread->GetRunSleepTime(), TRUE);
		}
 
		pThread->m_eThreadState = TS_STOP;
		return uRet;
	}
 
protected:
	THREAD_STATE m_eThreadState;
	HANDLE m_hPreparedEvt;
	ThreadNumber m_uTerminate;
	ThreadNumber m_uPause;
 
	HANDLE m_hThread;
	unsigned int m_uThreadID;
 
	DWORD m_dwRunSleepTime;
	DWORD m_dwLastRunCostTime;
};
//////////////////////////////////////////////////////////////////////////
#endif

封装了ICMP计算ping延迟的函数,返回值基于message,获取对应的自定义message即可。该封装线程安全。

#ifndef _INC_PING_THREAD_
#define _INC_PING_THREAD_
//////////////////////////////////////////////////////////////////////////
#include <WinSock2.h>
#include "ThreadRunner.h"
#include <list>
//////////////////////////////////////////////////////////////////////////
//	ping struct declaration
struct PingTask
{
	int nTaskID;
	char szDeskIP[20];
	ULONG ulInetIP;
};
typedef std::list<PingTask*> PingTaskList;
 
#define DEF_PACKET_SIZE 32
#define ECHO_REQUEST 8
#define ECHO_REPLY 0
 
#define DEF_PINGTIMEOUT	200
 
#pragma pack(push, 1)
 
struct IPHeader
{
	BYTE m_byVerHLen; //4位版本+4位首部长度
	BYTE m_byTOS; //服务类型
	USHORT m_usTotalLen; //总长度
	USHORT m_usID; //标识
	USHORT m_usFlagFragOffset; //3位标志+13位片偏移
	BYTE m_byTTL; //TTL
	BYTE m_byProtocol; //协议
	USHORT m_usHChecksum; //首部检验和
	ULONG m_ulSrcIP; //源IP地址
	ULONG m_ulDestIP; //目的IP地址
};
 
struct ICMPHeader
{ 
	BYTE m_byType; //类型
	BYTE m_byCode; //代码
	USHORT m_usChecksum; //检验和 
	USHORT m_usID; //标识符
	USHORT m_usSeq; //序号
	ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)
};
 
#pragma pack(pop)
 
struct PingReply
{
	USHORT m_usSeq;
	DWORD m_dwRoundTripTime;
	DWORD m_dwBytes;
	DWORD m_dwTTL;
};
//////////////////////////////////////////////////////////////////////////
DWORD GetTickCountCalibrate();
//////////////////////////////////////////////////////////////////////////
class PingThread : public ThreadRunner
{
public:
	PingThread();
	virtual ~PingThread();
 
public:
	virtual unsigned int Thread_DoWork();
 
public:
	bool Init();
	void UnInit();
 
	int AddTask(const char* _pszIP);
	bool RemoveTask(int _nTaskID);
	void ClearTask();
 
	DWORD GetPingTimeout()
	{
		return m_dwPingTimeout;
	}
	void SetPingTimeout(DWORD _dwTimeout)
	{
		m_dwPingTimeout = _dwTimeout;
	}
 
	void SetReceiverMsgID(DWORD _dwMsgID)
	{
		m_dwReceiverMsgID = _dwMsgID;
	}
	void SetReceiverHwnd(HWND _hReceiver)
	{
		m_hReceiverHwnd = _hReceiver;
	}
 
protected:
	void LockTaskList()
	{
		EnterCriticalSection(&m_stCriticalSection);
	}
	void UnlockTaskList()
	{
		LeaveCriticalSection(&m_stCriticalSection);
	}
	bool DoPingWork(const PingTask* _pTask);
	USHORT CalCheckSum(USHORT *pBuffer, int nSize);
 
protected:
	bool m_bInitOk;
	PingTaskList m_xPingTaskList;
	CRITICAL_SECTION m_stCriticalSection;
	int m_nTaskIDSeed;
	int m_nPingICMPSeed;
	//	ICMP buffer
	char* m_szICMPData;
	//	socket relative
	SOCKET m_socketICMP;
	WSAEVENT m_event;
	USHORT m_usCurrentProcID;
 
	//	settings
	DWORD m_dwPingTimeout;
 
	//	receiver
	DWORD m_dwReceiverMsgID;
	HWND m_hReceiverHwnd;
};
//////////////////////////////////////////////////////////////////////////
#endif

#include "PingThread.h"
//////////////////////////////////////////////////////////////////////////
#pragma comment(lib, "Ws2_32.lib")
//////////////////////////////////////////////////////////////////////////
ULONG GetTickCountCalibrate()
{
	static ULONG s_ulFirstCallTick = 0;
	static LONGLONG s_ullFirstCallTickMS = 0;
 
	SYSTEMTIME systemtime;
	FILETIME filetime;
	GetLocalTime(&systemtime);    
	SystemTimeToFileTime(&systemtime, &filetime);
	LARGE_INTEGER liCurrentTime;
	liCurrentTime.HighPart = filetime.dwHighDateTime;
	liCurrentTime.LowPart = filetime.dwLowDateTime;
	LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;
 
	if (s_ulFirstCallTick == 0)
	{
		s_ulFirstCallTick = GetTickCount();
	}
	if (s_ullFirstCallTickMS == 0)
	{
		s_ullFirstCallTickMS = llCurrentTimeMS;
	}
 
	return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
}
//////////////////////////////////////////////////////////////////////////
PingThread::PingThread()
{
	InitializeCriticalSection(&m_stCriticalSection);
	m_nTaskIDSeed = 0;
	m_nPingICMPSeed = 0;
	m_bInitOk = false;
	m_szICMPData = NULL;
	m_dwPingTimeout = DEF_PINGTIMEOUT;
	m_usCurrentProcID = 0;
	m_dwReceiverMsgID = 0;
	m_hReceiverHwnd = NULL;
}
 
PingThread::~PingThread()
{
 
}
 
//////////////////////////////////////////////////////////////////////////
bool PingThread::Init()
{
	WSADATA WSAData;
	WSAStartup(MAKEWORD(1, 1), &WSAData);
	m_event = WSACreateEvent();
	m_socketICMP = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);
 
	if (m_socketICMP != SOCKET_ERROR)
	{
		WSAEventSelect(m_socketICMP, m_event, FD_READ);
		m_szICMPData = new char[DEF_PACKET_SIZE + sizeof(ICMPHeader)];
		m_bInitOk = true;
	}
	else
	{
		UnInit();
	}
 
	return m_bInitOk;
}
 
void PingThread::UnInit()
{
	ClearTask();
	WSACleanup();
	delete[] m_szICMPData;
	m_szICMPData = NULL;
}
 
unsigned int PingThread::Thread_DoWork()
{
	LockTaskList();
 
	PingTaskList::iterator begIter = m_xPingTaskList.begin();
	PingTaskList::iterator endIter = m_xPingTaskList.end();
 
	for(begIter;
		begIter != endIter;
		++begIter)
	{
		PingTask* pTask = *begIter;
		DoPingWork(pTask);
	}
 
 
	UnlockTaskList();
 
	return 0;
}
 
int PingThread::AddTask(const char* _pszIP)
{
	unsigned long ulAddr = inet_addr(_pszIP);
	if(ulAddr == INADDR_NONE)
	{
		return 0;
	}
 
	LockTaskList();
 
	PingTask* pTask = new PingTask;
	strcpy(pTask->szDeskIP, _pszIP);
	pTask->ulInetIP = ulAddr;
	pTask->nTaskID = ++m_nTaskIDSeed;
	m_xPingTaskList.push_back(pTask);
 
	UnlockTaskList();
 
	return pTask->nTaskID;
}
 
bool PingThread::RemoveTask(int _nTaskID)
{
	LockTaskList();
 
	bool bRet = false;
	PingTaskList::iterator begIter = m_xPingTaskList.begin();
	PingTaskList::iterator endIter = m_xPingTaskList.end();
 
	for(begIter;
		begIter != endIter;
		)
	{
		PingTask* pTask = *begIter;
 
		if(0 == _nTaskID)
		{
			//	remove all
			delete pTask;
			pTask = NULL;
			begIter = m_xPingTaskList.erase(begIter);
		}
		else
		{
			if(pTask->nTaskID == _nTaskID)
			{
				delete pTask;
				pTask = NULL;
				m_xPingTaskList.erase(begIter);
				bRet = true;
				break;
			}
                        else{
				++begIter;
			}
		}
	}
 
	UnlockTaskList();
 
	if(0 == _nTaskID)
	{
		return true;
	}
	else
	{
		return bRet;
	}
}
 
void PingThread::ClearTask()
{
	RemoveTask(0);
}
 
bool PingThread::DoPingWork(const PingTask* _pTask)
{
	if(!m_bInitOk)
	{
		return false;
	}
 
	//配置SOCKET
	sockaddr_in sockaddrDest; 
	sockaddrDest.sin_family = AF_INET; 
	sockaddrDest.sin_addr.s_addr = _pTask->ulInetIP;
	int nSockaddrDestSize = sizeof(sockaddrDest);
 
	//构建ICMP包
	int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);
	ULONG ulSendTimestamp = GetTickCountCalibrate();
	USHORT usSeq = ++m_nPingICMPSeed;    
	memset(m_szICMPData, 0, nICMPDataSize);
	ICMPHeader *pICMPHeader = (ICMPHeader*)m_szICMPData;
	pICMPHeader->m_byType = ECHO_REQUEST; 
	pICMPHeader->m_byCode = 0; 
	pICMPHeader->m_usID = m_usCurrentProcID;    
	pICMPHeader->m_usSeq = usSeq;
	pICMPHeader->m_ulTimeStamp = ulSendTimestamp;
	pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);
 
	//发送ICMP报文
	if (sendto(m_socketICMP, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR)
	{
		return false;
	}
 
	char recvbuf[256] = {"\0"};
	while (TRUE)
	{
		//接收响应报文
		if (WSAWaitForMultipleEvents(1, &m_event, FALSE, m_dwPingTimeout, FALSE) != WSA_WAIT_TIMEOUT)
		{
			WSANETWORKEVENTS netEvent;
			WSAEnumNetworkEvents(m_socketICMP, m_event, &netEvent);
 
			if (netEvent.lNetworkEvents & FD_READ)
			{
				ULONG nRecvTimestamp = GetTickCountCalibrate();
				int nPacketSize = recvfrom(m_socketICMP, recvbuf, 256, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);
				if (nPacketSize != SOCKET_ERROR)
				{
					IPHeader *pIPHeader = (IPHeader*)recvbuf;
					USHORT usIPHeaderLen = (USHORT)((pIPHeader->m_byVerHLen & 0x0f) * 4);
					ICMPHeader *pICMPHeader = (ICMPHeader*)(recvbuf + usIPHeaderLen);
 
					if (pICMPHeader->m_usID == m_usCurrentProcID //是当前进程发出的报文
						&& pICMPHeader->m_byType == ECHO_REPLY //是ICMP响应报文
						&& pICMPHeader->m_usSeq == usSeq //是本次请求报文的响应报文
						)
					{
						/*pPingReply->m_usSeq = usSeq;
						pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp;
						pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);
						pPingReply->m_dwTTL = pIPHeader->m_byTTL;
						return TRUE;*/
						if(0 != m_dwReceiverMsgID &&
							NULL != m_hReceiverHwnd)
						{
							PostMessage(m_hReceiverHwnd, m_dwReceiverMsgID, _pTask->ulInetIP, nRecvTimestamp - pICMPHeader->m_ulTimeStamp);
							return true;
						}
					}
				}
			}
		}
		//超时
		if (GetTickCountCalibrate() - ulSendTimestamp >= m_dwPingTimeout)
		{
			PostMessage(m_hReceiverHwnd, m_dwReceiverMsgID, _pTask->ulInetIP, -1);
			return false;
		}
	}
}
 
USHORT PingThread::CalCheckSum(USHORT *pBuffer, int nSize)
{
	unsigned long ulCheckSum=0; 
	while(nSize > 1) 
	{ 
		ulCheckSum += *pBuffer++; 
		nSize -= sizeof(USHORT); 
	}
	if(nSize ) 
	{ 
		ulCheckSum += *(UCHAR*)pBuffer; 
	} 
 
	ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff); 
	ulCheckSum += (ulCheckSum >>16); 
 
	return (USHORT)(~ulCheckSum); 
}

使用也很简单

m_xPingThread.SetReceiverHwnd(GetSafeHwnd());
		m_xPingThread.SetReceiverMsgID(WM_USER_PINGMSG);
		m_xPingThread.AddTask("121.40.197.47");
		m_xPingThread.AddTask("11.111.11.111");
		m_xPingThread.SetRunSleepTime(1000);
		m_xPingThread.Run();

只需要处理对应消息即可。退出的时候注意需要结束线程及卸载资源

	if(m_xPingThread.GetThreadState() == ThreadRunner::TS_RUN)
	{
		m_xPingThread.Stop();
		ThreadRunner::THREAD_STATE ts = m_xPingThread.GetThreadState();
 
		while(ts == ThreadRunner::TS_RUN)
		{
			//	nothing
			ts = m_xPingThread.GetThreadState();
			Sleep(1000);
		}
		m_xPingThread.UnInit();
	}

共 0 条回复
暂时没有人回复哦,赶紧抢沙发
发表新回复

作者

sryan
today is a good day