Tracert 与 Ping 程序设计与实现(2024)

2024-01-07 09:44

本文主要是介绍Tracert 与 Ping 程序设计与实现(2024),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.题目描述

了解 Tracert 程序的实现原理,并调试通过。然后参考 Tracert 程序和计算机网络教材 4.4.2 节, 计算机网络 课程设计指导书 2 编写一个 Ping 程序,并能测试本局域网的所有机器是否在线,运行界面如下图所示的 QuickPing 程序。


2.程序Demo

aaf753f838634837989a1fc8fbb5e2bf.png


3.参考代码

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
#include "sstream"using namespace std;
#pragma comment(lib, "Ws2_32.lib")
//IP 报头
typedef struct {unsigned char hdr_len: 4;       //4 位头部长度unsigned char version: 4;       //4 位版本号unsigned char tos;              //8 位服务类型unsigned short total_len;       //16位总长度unsigned short identifier;      //16位标识符unsigned short frag_and_flags;  //3 位标志加 13 位片偏移unsigned char ttl;              //8 位生存时间unsigned char protocol;         //8 位上层协议号unsigned short checksum;        //16位校验和unsigned long sourceIP;         //32位源 IP 地址unsigned long destIP;           //32位目的 IP 地址
} IP_HEADER;
//ICMP 报头
typedef struct {BYTE type; //8 位类型字段BYTE code; //8 位代码字段USHORT cksum; //16 位校验和USHORT id; //16 位标识符USHORT seq; //16 位序列号
} ICMP_HEADER;
//报文解码结构
typedef struct {USHORT usSeqNo; //序列号DWORD dwRoundTripTime; //往返时间in_addr dwIPaddr; //返回报文的 IP 地址
} DECODE_RESULT;//计算网际校验和函数
USHORT checksum(USHORT *pBuf, int iSize) {unsigned long cksum = 0;while (iSize > 1) {cksum += *pBuf++;iSize -= sizeof(USHORT);}if (iSize) {cksum += *(UCHAR *) pBuf;}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >> 16);return (USHORT) (~cksum);
}//对数据包进行解码
BOOL DecodeIcmpResponse(char *pBuf, int iPacketSize, DECODE_RESULT &DecodeResult, BYTE ICMP_ECHO_REPLY, BYTE ICMP_TIMEOUT) {//检查数据报大小的合法性IP_HEADER *pIpHdr = (IP_HEADER *) pBuf;int iIpHdrLen = pIpHdr->hdr_len * 4;if (iPacketSize < (int) (iIpHdrLen + sizeof(ICMP_HEADER))) return FALSE;//根据 ICMP 报文类型提取 ID 字段和序列号字段ICMP_HEADER *pIcmpHdr = (ICMP_HEADER *) (pBuf + iIpHdrLen);USHORT usID, usSquNo;if (pIcmpHdr->type == ICMP_ECHO_REPLY) //ICMP 回显应答报文{usID = pIcmpHdr->id; //报文 IDusSquNo = pIcmpHdr->seq; //报文序列号} else if (pIcmpHdr->type == ICMP_TIMEOUT)//ICMP 超时差错报文{char *pInnerIpHdr = pBuf + iIpHdrLen + sizeof(ICMP_HEADER); //载荷中的 IP 头int iInnerIPHdrLen = ((IP_HEADER *) pInnerIpHdr)->hdr_len * 4; //载荷中的 IP 头长ICMP_HEADER *pInnerIcmpHdr = (ICMP_HEADER *) (pInnerIpHdr + iInnerIPHdrLen);//载荷中的 ICMP头usID = pInnerIcmpHdr->id; //报文 IDusSquNo = pInnerIcmpHdr->seq; //序列号} else {return false;}//检查 ID 和序列号以确定收到期待数据报if (usID != (USHORT) GetCurrentProcessId() || usSquNo != DecodeResult.usSeqNo) {return false;}//记录 IP 地址并计算往返时间DecodeResult.dwIPaddr.s_addr = pIpHdr->sourceIP;DecodeResult.dwRoundTripTime = GetTickCount() - DecodeResult.dwRoundTripTime;//处理正确收到的 ICMP 数据报if (pIcmpHdr->type == ICMP_ECHO_REPLY || pIcmpHdr->type == ICMP_TIMEOUT) {//输出往返时间信息if (DecodeResult.dwRoundTripTime)cout << " " << DecodeResult.dwRoundTripTime << "ms" << flush;elsecout << " " << "<1ms" << flush;}return true;
}// 数字转String
string num2str(int &num) {string str;stringstream ss;ss << num;ss >> str;return str;
}//提取IP
string GetIP(string ip) {char separator = '.';int i = 0, count = 3;// Temporary string used to split the string.string s;while (ip[i] != '\0') {if (ip[i] != separator) {s += ip[i];} else {s += ip[i];count--;}if (count == 0) {break;}i++;}return s;
}int main() {cout<<" *======Tracert 与 Ping 程序设计与实现======* "<<endl;//定义=====================================================================int iTimeout = 10;                    //超时时间const int DEF_MAX_HOP = 1;             //检查次数BOOLEAN Show_All = false;              //是否输出所有信息string Scan_ip;//ICMP 类型字段const BYTE ICMP_ECHO_REQUEST = 8;      //请求回显const BYTE ICMP_ECHO_REPLY = 0;        //回显应答const BYTE ICMP_TIMEOUT = 11;          //传输超时//其他常量定义const int DEF_ICMP_DATA_SIZE = 32;     //ICMP 报文默认数据字段长度const int MAX_ICMP_PACKET_SIZE = 1024; //ICMP 报文最大长度(包括报头)const DWORD DEF_ICMP_TIMEOUT = 100;    //回显应答超时时间int OnlineNum = 0;//=======================================================================cout << "请输入路由器IP:";cin >> Scan_ip;//初始化 Windows sockets 网络环境WSADATA wsa;WSAStartup(MAKEWORD(2, 2), &wsa);const char *IpAddress;string IpA;cout <<endl<<" 开始扫描:"<<endl;cout << "----------------------------------------------------------------" << endl;cout << "     耗时         机器IP           序号           状态          |" << endl;cout << "----------------------------------------------------------------" << endl;for (int i = 1; i < 254; i++) {IpA = GetIP(Scan_ip)+ num2str(i);IpAddress = IpA.c_str();// cout << IpA << endl;//得到 IP 地址u_long ulDestIP = inet_addr(IpAddress);//转换不成功时按域名解析if (ulDestIP == INADDR_NONE) {hostent *pHostent = gethostbyname(IpAddress);if (pHostent) {ulDestIP = (*(in_addr *) pHostent->h_addr).s_addr;} else {cout << "输入的 IP 地址或域名无效!" << endl;WSACleanup();return 0;}}//填充目地端 socket 地址sockaddr_in destSockAddr;ZeroMemory(&destSockAddr, sizeof(sockaddr_in));destSockAddr.sin_family = AF_INET;destSockAddr.sin_addr.s_addr = ulDestIP;//创建原始套接字SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);//接收超时setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char *) &iTimeout, sizeof(iTimeout));//发送超时setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char *) &iTimeout, sizeof(iTimeout));//填充 ICMP 报文中每次发送时不变的字段char IcmpSendBuf[sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE];//发送缓冲区memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); //初始化发送缓冲区char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE]; //接收缓冲区memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); //初始化接收缓冲区ICMP_HEADER *pIcmpHeader = (ICMP_HEADER *) IcmpSendBuf;pIcmpHeader->type = ICMP_ECHO_REQUEST; //类型为请求回显pIcmpHeader->code = 0; //代码字段为 0pIcmpHeader->id = (USHORT) GetCurrentProcessId(); //ID 字段为当前进程号memset(IcmpSendBuf + sizeof(ICMP_HEADER), 'E', DEF_ICMP_DATA_SIZE);//数据字段USHORT usSeqNo = 0; //ICMP 报文序列号int iTTL = 1; //TTL 初始值为 1BOOL bReachDestHost = FALSE; //循环退出标志int iMaxHot = DEF_MAX_HOP; //循环的最大次数DECODE_RESULT DecodeResult; //传递给报文解码函数的结构化参数while (!bReachDestHost && iMaxHot--) {//设置 IP 报头的 TTL 字段setsockopt(sockRaw, IPPROTO_IP, IP_TTL, (char *) &iTTL, sizeof(iTTL));//  cout << iTTL << flush; //输出当前序号//填充 ICMP 报文中每次发送变化的字段((ICMP_HEADER *) IcmpSendBuf)->cksum = 0; //校验和先置为 0((ICMP_HEADER *) IcmpSendBuf)->seq = htons(usSeqNo++); //填充序列号((ICMP_HEADER *) IcmpSendBuf)->cksum = checksum((USHORT *) IcmpSendBuf,sizeof(ICMP_HEADER) + DEF_ICMP_DATA_SIZE); //计算校验和//记录序列号和当前时间DecodeResult.usSeqNo = ((ICMP_HEADER *) IcmpSendBuf)->seq; //当前序号DecodeResult.dwRoundTripTime = GetTickCount(); //当前时间//发送 TCP 回显请求信息sendto(sockRaw, IcmpSendBuf, sizeof(IcmpSendBuf), 0, (sockaddr *) &destSockAddr, sizeof(destSockAddr));//接收 ICMP 差错报文并进行解析处理sockaddr_in from; //对端 socket 地址int iFromLen = sizeof(from); //地址结构大小int iReadDataLen; //接收数据长度while (true) {//接收数据iReadDataLen = recvfrom(sockRaw, IcmpRecvBuf, MAX_ICMP_PACKET_SIZE, 0, (sockaddr *) &from, &iFromLen);if (iReadDataLen != SOCKET_ERROR)//有数据到达{//对数据包进行解码if (DecodeIcmpResponse(IcmpRecvBuf, iReadDataLen, DecodeResult, ICMP_ECHO_REPLY, ICMP_TIMEOUT)) {//到达目的地,退出循环if (DecodeResult.dwIPaddr.s_addr == destSockAddr.sin_addr.s_addr)bReachDestHost = true;break;}} else if (WSAGetLastError() == WSAETIMEDOUT & Show_All) //接收超时,输出*号{cout << '\t' << "请求超时 " << DEF_MAX_HOP - iMaxHot << "次" << endl;break;} else {break;}}iTTL++; //递增 TTL 值}if (WSAGetLastError() != WSAETIMEDOUT) {cout << "         " << IpA << "            " << i << "            在线" << endl;OnlineNum++;if (Show_All)cout << "================================================================" << endl;} else if (WSAGetLastError() == WSAETIMEDOUT & Show_All) {cout << "         " << IpA << "             " << i << "           离线" << endl;cout << "================================================================" << endl;}}cout << "================================================================" << endl;cout << endl << "检测到 " << OnlineNum << " 台设备在线" << endl<< endl;system("pause");WSACleanup();return 0;
}

4.导入ws2_32库到Clion :

导入ws2_32库到Clion项目-CSDN博客

 2024 HNUST计算机网络课程设计-(ᕑᗢᓫ∗)˒芒果酱-参考文章

(代码可以参考,૮₍ ˃ ⤙ ˂ ₎ა 但同学们要认真编写哦)
-------------------------------------------------------------------------
1、网络聊天程序的设计与实现
C++ Socket 多线程 网络聊天室 支持用户端双向交流(2023)-CSDN博客
2、Tracert 与 Ping 程序设计与实现
Tracert 与 Ping 程序设计与实现(2024)-CSDN博客
3、滑动窗口协议仿真
滑动窗口协议仿真(2024)-CSDN博客
4、OSPF 路由协议原型系统设计与实现
OSPF 路由协议原型系统设计与实现-CSDN博客
5、基于 IP 多播的网络会议程序
基于 IP 多播的网络会议程序(2024)-CSDN博客
6、编程模拟 NAT 网络地址转换
编程模拟 NAT 网络地址转换(2024)-CSDN博客
7、网络嗅探器的设计与实现
网络嗅探器的设计与实现(2024)-转载-CSDN博客
8、网络报文分析程序的设计与实现
网络报文分析程序的设计与实现(2024)-CSDN博客
9、简单 Web Server 程序的设计与实现
简单 Web Server 程序的设计与实现 (2024)-CSDN博客
10、路由器查表过程模拟

计算机网络 - 路由器查表过程模拟 C++(2024)-CSDN博客

这篇关于Tracert 与 Ping 程序设计与实现(2024)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/579509

相关文章

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

在 Spring Boot 中实现异常处理最佳实践

《在SpringBoot中实现异常处理最佳实践》本文介绍如何在SpringBoot中实现异常处理,涵盖核心概念、实现方法、与先前查询的集成、性能分析、常见问题和最佳实践,感兴趣的朋友一起看看吧... 目录一、Spring Boot 异常处理的背景与核心概念1.1 为什么需要异常处理?1.2 Spring B

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too