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

news2024/11/15 10:28:09

基于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::chrono::milliseconds>(now.time_since_epoch()).count();

						timems = dwNowTime - dwTimeTransmit;
					}
					else
						goto GO_ON;

				}
				else
				{
					timems = -1;  //异常
				}

				m_iTxID++;
				m_iTxSequeNum++;

				break;
			}

	GO_ON:
			auto current_clock = std::chrono::system_clock::now();  
			DWORD dwCurrentTime = std::chrono::duration_cast<std::chrono::milliseconds>(current_clock.time_since_epoch()).count();;
			if (dwCurrentTime - dwSendTime > 2000)
			{
				timems = -2;  //超时
				return;
			}
		} 
		while (true);
	}

}


void InitWinSockEnv()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
}


void CleanupWinSockEnv()
{
	WSACleanup();
}

③、 PING多线程接口封装

多线程采用 std::thread 实现,线程函数封装如下:

/************************************************************************/
/*                                                                      */
/*  @WrapExecPing函数功能:  线程函数,调用PING接口                       */
/*                                                                      */
/*  @aipaddr, bipaddr参数: 监视的节点IPA和IPB地址                        */
/*  @atimems, btimems参数: IPA地址和IPB地址PING响应时间                  */
/*  @attl, bttl参数:       IPA地址和IPB地址PING响应TTL值                 */
/*  @stopf 参数:           停止线程任务标志位                            */
/*  @package_size 参数:    PING包大小                                   */
/*  @asnd, bsnd参数:       IPA地址和IPB地址PING次数                      */
/*  @f 参数:               线程结束标志位                                */
/*                                                                      */
/************************************************************************/
void WrapExecPing(std::string aipaddr, std::string bipaddr, int& atimems, int& attl, int& btimems, int& bttl, bool& stopf,int package_size,int& asnd,int&bsnd, bool& f)
{
	IPing aping;
	IPing bping;

    //设置PING包大小
	aping.SetPackSize(package_size);
	bping.SetPackSize(package_size);

	f = true;

	while (!stopf)
	{
		auto start = std::chrono::system_clock::now();
		DWORD dwStartTime = std::chrono::duration_cast<std::chrono::milliseconds>(start.time_since_epoch()).count();

		if (aipaddr.length() > 5)
		{
            //执行IP地址A的PING
			aping.PingHost(aipaddr.c_str(), atimems, attl);
			asnd++;
		}
		else 
			std::this_thread::sleep_for(std::chrono::milliseconds(500));
			
		if (bipaddr.length() > 5)
		{
            //执行IP地址B的PING
			bping.PingHost(bipaddr.c_str(), btimems, bttl);
			bsnd++;
		}
		else
			std::this_thread::sleep_for(std::chrono::milliseconds(500));

		auto now = std::chrono::system_clock::now();
		DWORD dwNowTime = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
		if (dwNowTime - dwStartTime < 500)
		{
			std::this_thread::sleep_for(std::chrono::milliseconds(800));
		}
	}

	f = false;
}

④、 QT主程序开发

【1】、 界面初始化
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

	//初始化Windows套接字环境
	InitWinSock();

	glb_bStopF = false;
	
	//初始化表格控件;
	initTableWidget();

	//初始化PING包大小复选框;
	initComboBox();

	//初始化延迟超限报警阈值;
	initLineEdit();
	
	ui->pushButtonStop->setEnabled(false);

	//设置控件样式表QSS
	setStyleSheet("QMainWindow{ background-color: #365a7a; } QLabel{ color:#E0E0E0; font-weight:bold; }");
	
	ui->pushButtonStart->setStyleSheet("QPushButton{ background-color: transparent;color: #f0f0f0; font-weight:bold;} QPushButton:hover{ background-color:white; color:gray; font-weight:thin; border-radius:4px;} QPushButton:disabled{ color:gray;}");
	ui->pushButtonStop->setStyleSheet("QPushButton{ background-color: transparent;color: #f0f0f0; font-weight:bold;} QPushButton:hover{ background-color:white; color:gray; font-weight:thin; border-radius:4px;} QPushButton:disabled{ color:gray;}");
	ui->lineEdit->setStyleSheet("QLineEdit{background-color:#D9D9D9; color:gray;}");
	ui->comboBox->setStyleSheet("QComboBox{color:gray;}");

	//信号槽定义;
	connect(ui->pushButtonStart, SIGNAL(clicked()), this, SLOT(onButtonStart()));
	connect(ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(onButtonStop()));
}

表格控件初始化

void MainWindow::initTableWidget()
{
	//加载nodecfg.ini文件

	extern bool LoadNodeConfig(CHostInfoArray& arry);
	if (false == LoadNodeConfig(arry) || arry.size() <= 0)
	{
		QMessageBox::warning(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("《nodecfg.ini》打开失败!"));
		return;
	}

	//初始化表格列
	ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
	ui->tableWidget->setColumnCount(MAX_COLUMN_NUM);

	QStringList headerList;
	headerList << QString::fromLocal8Bit("网络节点名称");
	headerList << QString::fromLocal8Bit("A网IP地址");
	headerList << QString::fromLocal8Bit("B网IP地址");
	headerList << QString::fromLocal8Bit("A网延时");
	headerList << QString::fromLocal8Bit("A网TTL");
	headerList << QString::fromLocal8Bit("B网延时");
	headerList << QString::fromLocal8Bit("B网TTL");
	headerList << QString::fromLocal8Bit("PING次数");
	ui->tableWidget->setHorizontalHeaderLabels(headerList);
	ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section {background-color: #365a7a; color: rgb(220,220,220); font-weight:bold;}");
	ui->tableWidget->verticalHeader()->setStyleSheet("QHeaderView::section {background-color: #365a7a; color: rgb(220,220,220); font-weight:bold;}");
	ui->tableWidget->setColumnWidth(0, 120);
	ui->tableWidget->setColumnWidth(1, 140);
	ui->tableWidget->setColumnWidth(2, 140);
	ui->tableWidget->setColumnWidth(7, 160);


	//行
	int iSize = arry.size();
	if (iSize > 0)
	{
		ui->tableWidget->setRowCount(iSize);

		for (int ii = 0; ii < iSize;++ii)
		{
			ui->tableWidget->setItem(ii, 0, new QTableWidgetItem());    ui->tableWidget->item(ii, 0)->setText(QString::fromStdString(arry[ii].strHostName)); ui->tableWidget->item(ii, 0)->setData(Qt::DisplayRole, QString::fromStdString(arry[ii].strHostName));
			ui->tableWidget->setItem(ii, 1, new QTableWidgetItem());    ui->tableWidget->item(ii, 1)->setText(QString::fromStdString(arry[ii].strIPA));
			ui->tableWidget->setItem(ii, 2, new QTableWidgetItem());    ui->tableWidget->item(ii, 2)->setText(QString::fromStdString(arry[ii].strIPB));
			ui->tableWidget->setItem(ii, 3, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 4, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 5, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 6, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 7, new QTableWidgetItem());
		}
	}
}

复选框控件初始化

void MainWindow::initComboBox()
{
	ui->comboBox->addItem("32", 32);
	ui->comboBox->addItem("128", 128);
	ui->comboBox->addItem("256", 256);
	ui->comboBox->addItem("512",512);
	ui->comboBox->addItem("1024", 1024);
	ui->comboBox->addItem("2048", 2048);
	ui->comboBox->addItem("2500", 2500);
	ui->comboBox->addItem("3000", 3000);
	ui->comboBox->addItem("4096", 4096);
	ui->comboBox->addItem("5000", 5000);
	ui->comboBox->addItem("8000", 8000);
	ui->comboBox->addItem("10000", 10000);
	ui->comboBox->addItem("13000", 13000);
	ui->comboBox->addItem("15000", 15000);
	ui->comboBox->addItem("18000", 18000);
	ui->comboBox->addItem("24000", 24000);
	ui->comboBox->addItem("28000", 28000);
	ui->comboBox->addItem("32000", 32000);
	ui->comboBox->addItem("36000", 36000);

	ui->comboBox->setCurrentIndex(0);
}

编辑框控件初始化

void MainWindow::initLineEdit()
{
	ui->lineEdit->setText("200");
}
【2】、 启动多线程

使用 std::thread线程,

void MainWindow::StartPingTask()
{
	int iSize = arry.size();
	if (iSize <= 0)
	{
		onButtonStop();
		return;
	}

	//报警阈值
	int alarmval = ui->lineEdit->text().toInt();

	//Ping包大小;
	int index = ui->comboBox->currentIndex();
	int package_size = ui->comboBox->itemData(index).toInt();

	SPINGINFO* pPingInfo = new SPINGINFO[iSize];

	for (int i = 0; i < iSize; i++)
	{
		pPingInfo[i].host = arry[i];
		pPingInfo[i].attl = -1;
		pPingInfo[i].bttl = -1;
		pPingInfo[i].atimems = -1;
		pPingInfo[i].btimems = -1;
		pPingInfo[i].asnd = 0;
		pPingInfo[i].bsnd = 0;

		std::thread T1(WrapExecPing, pPingInfo[i].host.strIPA, pPingInfo[i].host.strIPB, std::ref(pPingInfo[i].atimems), std::ref(pPingInfo[i].attl), std::ref(pPingInfo[i].btimems), std::ref(pPingInfo[i].bttl), std::ref(glb_bStopF), package_size, std::ref(pPingInfo[i].asnd), std::ref(pPingInfo[i].bsnd), std::ref(pPingInfo[i].runf));


		pPingInfo[i].t = std::move(T1);

		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
}
【3】、 完整代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QMessageBox"
#include "public.h"
#include "IPing.h"
#include <thread>
#include <chrono>


#define  MAX_COLUMN_NUM     8

CHostInfoArray arry;
bool glb_bStopF = false;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

	//初始化Windows套接字环境
	InitWinSock();

	glb_bStopF = false;
	
	//初始化表格控件;
	initTableWidget();

	//初始化PING包大小复选框;
	initComboBox();

	//初始化延迟超限报警阈值;
	initLineEdit();
	
	ui->pushButtonStop->setEnabled(false);

	//设置控件样式表QSS
	setStyleSheet("QMainWindow{ background-color: #365a7a; } QLabel{ color:#E0E0E0; font-weight:bold; }");
	
	ui->pushButtonStart->setStyleSheet("QPushButton{ background-color: transparent;color: #f0f0f0; font-weight:bold;} QPushButton:hover{ background-color:white; color:gray; font-weight:thin; border-radius:4px;} QPushButton:disabled{ color:gray;}");
	ui->pushButtonStop->setStyleSheet("QPushButton{ background-color: transparent;color: #f0f0f0; font-weight:bold;} QPushButton:hover{ background-color:white; color:gray; font-weight:thin; border-radius:4px;} QPushButton:disabled{ color:gray;}");
	ui->lineEdit->setStyleSheet("QLineEdit{background-color:#D9D9D9; color:gray;}");
	ui->comboBox->setStyleSheet("QComboBox{color:gray;}");

	//信号槽定义;
	connect(ui->pushButtonStart, SIGNAL(clicked()), this, SLOT(onButtonStart()));
	connect(ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(onButtonStop()));
}

MainWindow::~MainWindow()
{
	CleanWinSock();

    delete ui;
}

void MainWindow::InitWinSock()
{
    //初始化Windows套接字环境
	InitWinSockEnv();
}

void MainWindow::CleanWinSock()
{
	CleanupWinSockEnv();
}

void MainWindow::initTableWidget()
{
	//加载网络节点配置文件nodecfg.ini
	extern bool LoadNodeConfig(CHostInfoArray& arry);
	if (false == LoadNodeConfig(arry) || arry.size() <= 0)
	{
		QMessageBox::warning(this, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("《nodecfg.ini》打开失败!"));
		return;
	}

	//初始化表格列
	ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
	ui->tableWidget->setColumnCount(MAX_COLUMN_NUM);

	QStringList headerList;
	headerList << QString::fromLocal8Bit("网络节点名称");
	headerList << QString::fromLocal8Bit("A网IP地址");
	headerList << QString::fromLocal8Bit("B网IP地址");
	headerList << QString::fromLocal8Bit("A网延时");
	headerList << QString::fromLocal8Bit("A网TTL");
	headerList << QString::fromLocal8Bit("B网延时");
	headerList << QString::fromLocal8Bit("B网TTL");
	headerList << QString::fromLocal8Bit("PING次数");
	ui->tableWidget->setHorizontalHeaderLabels(headerList);
	ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section {background-color: #365a7a; color: rgb(220,220,220); font-weight:bold;}");
	ui->tableWidget->verticalHeader()->setStyleSheet("QHeaderView::section {background-color: #365a7a; color: rgb(220,220,220); font-weight:bold;}");
	ui->tableWidget->setColumnWidth(0, 120);
	ui->tableWidget->setColumnWidth(1, 140);
	ui->tableWidget->setColumnWidth(2, 140);
	ui->tableWidget->setColumnWidth(7, 160);


	//行,插入记录
	int iSize = arry.size();
	if (iSize > 0)
	{
		ui->tableWidget->setRowCount(iSize);

		for (int ii = 0; ii < iSize;++ii)
		{
			ui->tableWidget->setItem(ii, 0, new QTableWidgetItem());    ui->tableWidget->item(ii, 0)->setText(QString::fromStdString(arry[ii].strHostName)); ui->tableWidget->item(ii, 0)->setData(Qt::DisplayRole, QString::fromStdString(arry[ii].strHostName));
			ui->tableWidget->setItem(ii, 1, new QTableWidgetItem());    ui->tableWidget->item(ii, 1)->setText(QString::fromStdString(arry[ii].strIPA));
			ui->tableWidget->setItem(ii, 2, new QTableWidgetItem());    ui->tableWidget->item(ii, 2)->setText(QString::fromStdString(arry[ii].strIPB));
			ui->tableWidget->setItem(ii, 3, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 4, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 5, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 6, new QTableWidgetItem());
			ui->tableWidget->setItem(ii, 7, new QTableWidgetItem());
		}
	}

	
}

void MainWindow::initComboBox()
{
    //PING包大小选项
	ui->comboBox->addItem("32", 32);
	ui->comboBox->addItem("128", 128);
	ui->comboBox->addItem("256", 256);
	ui->comboBox->addItem("512",512);
	ui->comboBox->addItem("1024", 1024);
	ui->comboBox->addItem("2048", 2048);
	ui->comboBox->addItem("2500", 2500);
	ui->comboBox->addItem("3000", 3000);
	ui->comboBox->addItem("4096", 4096);
	ui->comboBox->addItem("5000", 5000);
	ui->comboBox->addItem("8000", 8000);
	ui->comboBox->addItem("10000", 10000);
	ui->comboBox->addItem("13000", 13000);
	ui->comboBox->addItem("15000", 15000);
	ui->comboBox->addItem("18000", 18000);
	ui->comboBox->addItem("24000", 24000);
	ui->comboBox->addItem("28000", 28000);
	ui->comboBox->addItem("32000", 32000);
	ui->comboBox->addItem("36000", 36000);

	ui->comboBox->setCurrentIndex(0);
}

void MainWindow::initLineEdit()
{
    //报警阈值,单位毫秒
	ui->lineEdit->setText("200");
}

//开始检测
void MainWindow::onButtonStart()
{
	ui->comboBox->setEnabled(false);
	ui->lineEdit->setEnabled(false);
	ui->pushButtonStart->setEnabled(false);
	ui->pushButtonStop->setEnabled(true);

	glb_bStopF = false;

	ClearTableWidget();

	StartPingTask();
}

void MainWindow::onButtonStop()
{
	glb_bStopF = true;
}


/************************************************************************/
/*                                                                      */
/*  @WrapExecPing函数功能: 线程函数,调用PING接口                        */
/*                                                                      */
/*  @aipaddr, bipaddr参数: 监视的节点IPA和IPB地址                        */
/*  @atimems, btimems参数: IPA地址和IPB地址PING响应时间                  */
/*  @attl, bttl参数:       IPA地址和IPB地址PING响应TTL值                 */
/*  @stopf 参数:           停止线程任务标志位                            */
/*  @package_size 参数:    PING包大小                                   */
/*  @asnd, bsnd参数:       IPA地址和IPB地址PING次数                      */
/*  @f 参数:               线程结束标志位                                */
/*                                                                      */
/************************************************************************/
void WrapExecPing(std::string aipaddr, std::string bipaddr, int& atimems, int& attl, int& btimems, int& bttl, bool& stopf,int package_size,int& asnd,int&bsnd, bool& f)
{
	IPing aping;
	IPing bping;

	aping.SetPackSize(package_size);
	bping.SetPackSize(package_size);

	f = true;

	while (!stopf)
	{
		auto start = std::chrono::system_clock::now();
		DWORD dwStartTime = std::chrono::duration_cast<std::chrono::milliseconds>(start.time_since_epoch()).count();

		if (aipaddr.length() > 5)
		{
			aping.PingHost(aipaddr.c_str(), atimems, attl);
			asnd++;
		}
		else 
			std::this_thread::sleep_for(std::chrono::milliseconds(500));
			
		if (bipaddr.length() > 5)
		{
			bping.PingHost(bipaddr.c_str(), btimems, bttl);
			bsnd++;
		}
		else
			std::this_thread::sleep_for(std::chrono::milliseconds(500));

		auto now = std::chrono::system_clock::now();
		DWORD dwNowTime = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
		if (dwNowTime - dwStartTime < 500)
		{
			std::this_thread::sleep_for(std::chrono::milliseconds(800));
		}
	}

	f = false;
}

void MainWindow::ClearTableWidget()
{
	int iRowCount = ui->tableWidget->rowCount();
	for (int k = 0; k < iRowCount; ++k)
	{
		for (int i = 3; i < MAX_COLUMN_NUM;++i)
		{
			ui->tableWidget->item(k, i)->setText(QString(""));
		}
	}
}

void MainWindow::StartPingTask()
{
	int iSize = arry.size();
	if (iSize <= 0)
	{
		onButtonStop();
		return;
	}

	//报警阈值
	int alarmval = ui->lineEdit->text().toInt();

	//Ping包大小;
	int index = ui->comboBox->currentIndex();
	int package_size = ui->comboBox->itemData(index).toInt();

	SPINGINFO* pPingInfo = new SPINGINFO[iSize];

	for (int i = 0; i < iSize; i++)
	{
		pPingInfo[i].host = arry[i];
		pPingInfo[i].attl = -1;
		pPingInfo[i].bttl = -1;
		pPingInfo[i].atimems = -1;
		pPingInfo[i].btimems = -1;
		pPingInfo[i].asnd = 0;
		pPingInfo[i].bsnd = 0;

        //启动线程
		std::thread T1(WrapExecPing, pPingInfo[i].host.strIPA, pPingInfo[i].host.strIPB, std::ref(pPingInfo[i].atimems), std::ref(pPingInfo[i].attl), std::ref(pPingInfo[i].btimems), std::ref(pPingInfo[i].bttl), std::ref(glb_bStopF), package_size, std::ref(pPingInfo[i].asnd), std::ref(pPingInfo[i].bsnd), std::ref(pPingInfo[i].runf));


		pPingInfo[i].t = std::move(T1);

		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}

    //界面更新
	do 
	{
		if (glb_bStopF) break;

		int iRowCount = ui->tableWidget->rowCount();
		for (int k = 0; k < iRowCount;++k)
		{
			QString strHostName = ui->tableWidget->item(k, 0)->data(Qt::DisplayRole).toString();

			for (int n = 0; n < iSize;++n)
			{
				if (strHostName.toStdString() == pPingInfo[n].host.strHostName)
				{
					if (pPingInfo[n].atimems == -1)
						ui->tableWidget->item(k, 3)->setText(QString("---"));
					else if (pPingInfo[n].atimems == -2)
						ui->tableWidget->item(k, 3)->setText(QString::fromLocal8Bit("超时"));
					else
					{
						ui->tableWidget->item(k, 3)->setText(QString("%1ms").arg(pPingInfo[n].atimems));

						if (pPingInfo[n].atimems > alarmval)
							ui->tableWidget->item(k, 3)->setBackgroundColor(QColor(255, 0, 0));    //超限,红色提示
						else
							ui->tableWidget->item(k, 3)->setBackgroundColor(QColor(255, 255, 255));
					}
						
					if (pPingInfo[n].attl < 0)
						ui->tableWidget->item(k, 4)->setText(QString("---"));
					else
						ui->tableWidget->item(k, 4)->setText(QString("%1").arg(pPingInfo[n].attl));

					if (pPingInfo[n].btimems == -1)
						ui->tableWidget->item(k, 5)->setText(QString("---"));
					else if (pPingInfo[n].btimems == -2)
						ui->tableWidget->item(k, 5)->setText(QString::fromLocal8Bit("超时"));
					else
					{
						ui->tableWidget->item(k, 5)->setText(QString("%1ms").arg(pPingInfo[n].btimems));

						if (pPingInfo[n].btimems > alarmval)
							ui->tableWidget->item(k, 5)->setBackgroundColor(QColor(255, 0, 0));     //超限,红色提示
						else
							ui->tableWidget->item(k, 5)->setBackgroundColor(QColor(255, 255, 255));
					}
						

					if (pPingInfo[n].bttl < 0)
						ui->tableWidget->item(k, 6)->setText(QString("---"));
					else
						ui->tableWidget->item(k, 6)->setText(QString("%1").arg(pPingInfo[n].bttl));

					QString strSndFrame = QString::fromLocal8Bit("A网:%1 | B网:%2").arg(pPingInfo[n].asnd, 3, 10, QLatin1Char('0')).arg(pPingInfo[n].bsnd, 3, 10, QLatin1Char('0'));
					ui->tableWidget->item(k, 7)->setText(strSndFrame);

					break;
				}
			}
		}
	} 
	while (true);

	ui->pushButtonStop->setEnabled(false);

	bool bRunningF = false;
	do 
	{
		bRunningF = false;

		for (int ii = 0; ii < iSize; ++ii)
		{
			if (pPingInfo[ii].runf == true)
			{
				ui->pushButtonStop->setText(QString::fromLocal8Bit("停止中..."));

				bRunningF = true;
				break;
			}
		}

	} 
	while (bRunningF);

	
	for (int ii = 0; ii < iSize;++ii)
	{
		pPingInfo[ii].t.detach();
	}

	delete []pPingInfo;

	ui->pushButtonStop->setText(QString::fromLocal8Bit("停止检测"));
	ui->pushButtonStart->setEnabled(true);
	ui->pushButtonStop->setEnabled(false);
	ui->comboBox->setEnabled(true);
	ui->lineEdit->setEnabled(true);
}

3、 运行效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微深节能 库区智能化无人天车管理系统 格雷母线

格雷母线在库区智能化无人天车管理系统的应用中&#xff0c;发挥了至关重要的作用。 一、系统构成与原理 系统构成&#xff1a; 格雷母线高精度位移测量系统主要由格雷母线、天线箱、地址解码器、地址编码器四个核心部分组成。这些组件协同工作&#xff0c;实现对移动设备的精确…

c++41两头堵模型

直接拷到自己的内存空间 字符串反转 递归&#xff1a;参数的入栈模型 函数的调用模型 先被调用的模型后执行 向局部变量拷贝内存 传两个参数 做函数结果

【解析几何笔记】1.课程介绍与要求

听的是B站UP主唐小谦的解析几何课&#xff0c;万年的老计算机专业人也想学数学OWO。 1. 课程介绍与要求 前面都是老师的课程介绍&#xff0c;从板书证明开始记 【证明】在三角形ABC中&#xff0c;D为BC边的中点&#xff0c;证明&#xff1a; ∠ ABC 9 0 ∘ \angle \text{ABC…

出现 AWS ECS 错误:集群中未找到容器实例处理办法?

使用部署docker容器映像&#xff0c;但未创建 EC2 实例的情况下。出现下面错误提示。 “调用 RunTask 操作时发生客户端错误 (InvalidParameterException)&#xff1a;在您的集群中未找到容器实例。” 经过以下的步骤&#xff1a; 1.将 Docker 映像从 Ubuntu 推送到我的 Amazo…

c++ - 特殊类设计

文章目录 一、设计一个不允许拷贝的类二、设计一个只能在堆上实例对象的类三、设计一个只能在栈上创建对象的类四、设计一个不能被继承的类五、设计一个只能创建一个对象的类&#xff08;单例模式&#xff09; 一、设计一个不允许拷贝的类 1、方法一&#xff1a;将拷贝构造和赋…

在Windows上配置VSCode MinGW+CMake(包括C++多线程编程的两套API:posix和win32)

创建目录 首先&#xff0c;需要电脑上安装VSCode, 并且创建三个文件夹&#xff1a;cmake、MinGW-posix、MinGW-w32 文件下载 下载posix-seh posix和win32分别是c多线程变成的两套API,可根据不同需求安装&#xff0c;现在先下载配置环境需要的几个文件 百度搜索MinGW-64 点…

Django 链接MySQL数据库,报错Did you install mysqlclient?

据说是在python3里面&#xff0c;已经用pymysql替换了MySQLdb来进行数据库连接 所以&#xff0c;先安装pymysql pip install pymysql之后为了测试这个问题是否和mysql-connector-c有关系&#xff0c;我提前把这个应用给卸了。 之后在整个项目根目录的init文件内写入以下内容 im…

在docker中进行日志切割

先在Linux中安装docker&#xff0c;然后在docker中安装appnode面板&#xff0c;并进行docker网络端口映射。接着进入docker&#xff0c;进行nginx日志切割。 安装docker 第一步&#xff0c;卸载旧版本docker。 若系统中已安装旧版本docker&#xff0c;则需要卸载旧版本docke…

大模型在资源全生命周期的应用探索

资源全生命周期管理的传统价值 运营商的网络涉及接入网、数据网、承载网、核心网、传输网、无线网、光缆网、云专网、动力网、业务平台等十数类大专业。网络资源的全生命周期体现在以下六大生产活动环节&#xff1a;网络规划→网络设计→网络工程建设→网络资源的投入使用→网络…

数据安全防护措施有哪些?防数据泄露的10大措施丨让你一次性看够!

古时烽火传信&#xff0c;密语藏于竹简之间&#xff0c;以防外泄&#xff0c;保家国安宁。 今朝数字洪流&#xff0c;数据如织&#xff0c;信息安全之重&#xff0c;不亚于昔日之密信。 在信息爆炸的时代&#xff0c;数据安全防护犹如筑起铜墙铁壁&#xff0c;以防数据泄露之患…

想要数字人直播平台赚钱,前期源码部署要注意哪些要点?

随着人工智能时代的到来&#xff0c;数字人直播的应用频率不断升高&#xff0c;展现巨大收益潜力的同时&#xff0c;也让不少想要通过数字人源码厂商搭建数字人直播平台的创业者产生好奇&#xff0c;并开始从各方面打听数字人直播平台怎么赚钱等相关问题的答案。 本期&#xf…

开营啦!| 上海交通大学 AI for Bioengineering 暑期学校开营仪式圆满举行!

开营仪式 2024年8月12日 &#xff0c;“AI for Bioengineering暑期学校”在上海交通大学闵行校区理科群楼300号报告厅开幕。本次暑期学校吸引了来自国内外30余所高校&#xff08;包括芝加哥大学、曼彻斯特大学、哥伦比亚大学、爱丁堡大学、南加利福尼亚大学、北京大学、清华大…

element-plus的表单输入框有清除按钮的,文字输入前后宽度不一致怎么解决

输入内容之后多了一个可清除的图标&#xff0c;输入框的宽度也被撑开了 根据输入前后的dom对比发现&#xff0c;多了一个图标的span标签 :deep(.el-input__wrapper) {position: relative;.el-input__inner {padding-right: 18px;}.el-input__suffix {position: absolute;right:…

服务器重启后的端口占用分析及解决方案

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Android Studio报错 Failed to transform ‘...‘ using Jetifier. Reason null

Android Studio报错 Failed to transform ‘…‘ using Jetifier. Reason null 问题描述&#xff1a; AndroidX提示Failed to transform ‘/…/’ using Jetifier. Reason: null. 解决方案&#xff1a; 在gradle.properties中&#xff0c;将 android.enableJetifiertrue改为…

uniapp 对于scroll-view滑动和页面滑动的联动处理

需求 遇到一个需求 解决方案 这个时候可以做一个内页面滑动判断 <!-- scroll-y 做true或者false的判断是否滑动 --> <view class"u-menu-wrap" style"background-color: #fff;"><scroll-view :scroll-y"data.isGo" scroll-wit…

mongodb连表查询,postman使用

要实现与SQL类似的查询&#xff0c;你需要使用聚合框架&#xff08;Aggregation Framework&#xff09; SELECT b.name, a.* FROM user a LEFT JOIN order b ON a.id b.id WHERE b.name LIKE %acd%; 从MongoDB 3.2版本开始&#xff0c;引入了聚合框架中的$lookup阶段&#xf…

【JS】详解浏览器的5 种Observer: Mutation、Intersection、Performance、Resize、Reporting

文章目录 1、IntersectionObserver 交叉观察器用法使用场景 2、MutationObserver 变动观察器用法使用场景 3、ResizeObserver 尺寸变化观察器用法使用场景 4、PerformanceObserver 性能观察器用法使用场景 5、ReportingObserver用法使用场景 总结 网页开发中我们经常要处理用户…

第三方jar自带logback导致本地日志文件不生成

1.问题及解决 这是依赖的jar包&#xff0c;自己有logback&#xff0c;只打印到控制台&#xff0c;导致我们项目里配置的error级别日志不会生成到日志文件中去。ai给的答案是自己控制加载顺序&#xff0c;但很麻烦&#xff0c;--logging.config也不行&#xff0c;最好下了个7z压…

Grafana 可视化监控和告警

前言 在现代分布式系统和云原生环境中&#xff0c;为了确保复杂的分布式系统和服务的高可用性、可靠性和性能&#xff0c;通常采用实时可视化监控和分析&#xff0c;实现故障快速响应、资源优化和安全保障&#xff0c;从而提升用户满意度和运营效率。 在目前主流的解决方案中…