基于ICMP(Ping)的多线程网络通道监视程序(QT)开发

基于ICMP(Ping)的多线程网络通道监视程序(QT)开发

1、 ICMP原理简介

可参考 ICMP(Ping)功能原理及其C++实现简介

2、 网络通道监视程序开发

设计原理: 通过PING 功能实现服务器、交换机、网闸等设备的网络检测,判断网络的否可达和TTL计算 。

具备功能:

  • 通过多线程,实现多个网络通道同时检测;
  • 支持动态加包。
  • 支持设置网络延迟阈值,超过阈值时提示用户。

①、 界面设计

程序采用QT开发,UI界面如下图所示:

在这里插入图片描述

中心区域为 QTableWidget 控件。

②、 PING接口封装

IPing.h :

#pragma once


class IPing
{
   
public:
	IPing();
	~IPing();

	void SetPackSize(int isize);

	void PingHost(const char* ip, int& timems, int& ttl);

private:
	int sock;
	
	unsigned int m_iTxID;
	unsigned int m_iTxSequeNum;

	unsigned int m_iSendPackageSize;
};


void InitWinSockEnv();

void CleanupWinSockEnv();

IPing.cxx:

#include "IPing.h"

#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <iomanip>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")


#define ICMP_PING_DATA_SIZE           40000     //填充数据长度;
#define ICMP_TYPE_PING_REQUEST        8
#define ICMP_TYPE_PING_REPLY          0

#define ICMP_PING_TIMES               1         //Ping次数
#define MAX_BUFFER_SIZE               40100


typedef unsigned char        uint8;
typedef unsigned short		 uint16;
typedef unsigned int         uint32;

//ICMP校验和计算
uint16 MakeChecksum(char* icmp_packet, int size)
{
   
	uint16 * sum = (uint16*)icmp_packet;
	uint32 checksum = 0;
	while (size > 1)
	{
   
		checksum += ntohs(*sum++);
		size -= sizeof(uint16);
	}

	if (size)
	{
   
		*sum = *((uint8*)sum);
		checksum += ((*sum << 8) & 0xFF00);
	}

	checksum = (checksum >> 16) + (checksum & 0xffff);
	checksum += checksum >> 16;

	return (uint16)(~checksum);
}

IPing::IPing()
{
   
	sock = 0;
	m_iTxID = 0;
	m_iTxSequeNum = 0;

	m_iSendPackageSize = 32;

	SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	sock = s;
}

IPing::~IPing()
{
   
	if (sock > 0)
	{
   
		closesocket(sock);
	}
}

void IPing::SetPackSize(int isize)
{
   
	m_iSendPackageSize = isize;
}

void IPing::PingHost(const char* ip, int& timems, int& ttl)
{
   
	std::string strHost = std::string(ip);
    if (strHost.length()< 5)
    {
   
		timems = -1;
		ttl = -1;
		return;
    }

	struct sockaddr_in pingaddr;
	memset((char *)&pingaddr, 0, sizeof(pingaddr));
	pingaddr.sin_family = AF_INET;
	pingaddr.sin_port = 0;
	pingaddr.sin_addr.s_addr = inet_addr(strHost.c_str());

	for (int ii = 0; ii < ICMP_PING_TIMES; ++ii)
	{
   
		//组帧
		uint8 ucCmdBuf[MAX_BUFFER_SIZE] = {
    0 };
		uint8* pCurr = ucCmdBuf;

		*pCurr++ = ICMP_TYPE_PING_REQUEST;		 //Type
		*pCurr++ = 0x00;						 //Code
		*pCurr++ = 0x00;						 //Checksum
		*pCurr++ = 0x00;						 //Checksum
		*pCurr++ = HIBYTE(m_iTxID);				 //Identifier
		*pCurr++ = LOBYTE(m_iTxID);				 //Identifier
		*pCurr++ = HIBYTE(m_iTxSequeNum);        //Sequence Number
		*pCurr++ = LOBYTE(m_iTxSequeNum);	     //Sequence Number

		auto send_clock = std::chrono::system_clock::now();
		DWORD dwSendTime = std::chrono::duration_cast<std::chrono::milliseconds>(send_clock.time_since_epoch()).count();;
		*pCurr++ = HIBYTE(HIWORD(dwSendTime));   //Current TickCount
		*pCurr++ = LOBYTE(HIWORD(dwSendTime));   //Current TickCount
		*pCurr++ = HIBYTE(LOWORD(dwSendTime));   //Current TickCount
		*pCurr++ = LOBYTE(LOWORD(dwSendTime));   //Current TickCount

		//Data
		for (int k = 0; k < m_iSendPackageSize - 4; ++k)
		{
   
			*pCurr++ = 0x61 + (k % 20);
		}

		uint16 usCheckSum = MakeChecksum((char*)ucCmdBuf, pCurr - ucCmdBuf);
		ucCmdBuf[2] = HIBYTE(usCheckSum);
		ucCmdBuf[3] = LOBYTE(usCheckSum);


		int txlen = sendto(sock, (char *)&ucCmdBuf, pCurr - ucCmdBuf, 0, (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in));

		uint8 ucRxBuf[MAX_BUFFER_SIZE] = {
    0 };

		struct sockaddr_in rxaddr;
		memset((char *)&rxaddr, 0, sizeof(rxaddr));
		rxaddr.sin_family = AF_INET;
		rxaddr.sin_port = 0;
		rxaddr.sin_addr.s_addr = inet_addr(strHost.c_str());
		int iSize = sizeof(struct sockaddr_in);


		do 
		{
   
			int rxlen = recvfrom(sock, (char *)&ucRxBuf, sizeof(ucRxBuf), 0, (struct sockaddr *)&rxaddr, &iSize);    
			if (rxaddr.sin_addr.S_un.S_addr == pingaddr.sin_addr.S_un.S_addr)
			{
   	
				if (rxlen >= 0)
				{
   
					//IP帧获取TTL
					ttl = ucRxBuf[8];

					//跳过IP Header 20个字节
					uint8* pIcmpFrame = ucRxBuf + 20;

					//Type和Code
					uint8 ucType = pIcmpFrame[0];
					uint8 ucCode = pIcmpFrame[1];
					if (ucCode != 0x00 || ucType != 0x00)
						goto GO_ON;

					//比对ID和序号
					uint16 iRxID = pIcmpFrame[4] * 256 + pIcmpFrame[5];
					uint16 iRxSequeNum = pIcmpFrame[6] * 256 + pIcmpFrame[7];
					if (iRxID == m_iTxID && iRxSequeNum == m_iTxSequeNum)
					{
   
						DWORD dwTimeTransmit = pIcmpFrame[8] * 256 * 256 * 256 + pIcmpFrame[9] * 256 * 256 + pIcmpFrame[10] * 256 + pIcmpFrame[11];

						auto now = std::chrono::system_clock::now();
						DWORD dwNowTime = std::chrono::duration_cast<std
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值