首页/新闻资讯/正文详情

Java实现PING程序:ICMP协议与原始套接字详解

发布时间:2026/9/24 13:38:59 来源:云帆数科 栏目:资讯中心
Java实现PING程序:ICMP协议与原始套接字详解
简介这份计算机网络课程设计报告围绕PING程序的设计与实现展开面向高校计算机、网络工程等专业需要完成课程设计的学生以及希望理解ICMP协议与Java网络编程的初学者。报告以模拟Windows下ping命令为目标涵盖问题描述、概要设计、详细设计、调试分析、心得体会与用户手册等完整章节可直接作为课程设计范文或模板参考。资源包共1个doc文件约1.88MB内容包含Ping、Timer、From、ImagePanel等类的设计思路pingRang与pingAddress核心算法代码以及InetAddress.isReachable方法的调用说明和异常处理方案。目前已有512人学习下载。读者可从中获得完整的课程设计结构框架、Java实现ping连通性检测的代码示例、Eclipse调试经验与常见问题解决思路适合作为网络课程设计报告撰写与网络编程入门的实践素材。1. 从一份课程设计报告说起PING 程序到底在测什么很多人第一次拿到「PING 程序设计与实现」这个题目脑子里冒出来的第一个念头是ping命令我天天用敲一下ping www.baidu.com看通不通就完事了这有什么好设计的但真坐到 Eclipse 前面打开 Java 准备写的时候问题就来了——ping到底发的是什么包为什么它不需要建立连接就能知道对面活着InetAddress.isReachable()为什么有时候返回 true 有时候返回 false跟系统权限有什么关系这份课程设计报告的核心其实不是让你复刻一个命令行工具而是逼你把 ICMP 协议、原始套接字、Java 网络编程这三块知识串起来。你需要自己构造 ICMP 回显请求报文自己算校验和自己解析回显应答最后统计往返时延和丢包率。适合正在做网络课程设计的学生也适合想从「会用 ping」进阶到「懂 ping 怎么实现」的后端开发。下面我按实际动手的顺序把这条路走一遍。2. ICMP 报文结构与 Java 原始套接字的选型理由2.1 为什么不能直接用 URLConnection 或 Socketping走的是 ICMP 协议不是 TCP 也不是 UDP。Java 标准库里的Socket和DatagramSocket分别对应 TCP 和 UDP它们封装的是传输层而 ICMP 属于网络层协议没有端口号的概念。所以你不能用new Socket()去发 ICMP 包这条路从根上就走不通。那 Java 有没有现成的 ICMP 接口有InetAddress.isReachable(int timeout)底层就是发 ICMP 回显请求。但它有几个致命限制第一它只返回一个布尔值你拿不到 RTT往返时延也拿不到 TTL第二在 Windows 上它有时候会退化成 TCP 的 7 号端口探测结果不准第三你没法控制 ICMP 报文的标识符和序列号做不了多包统计。课程设计要的是完整的 ping 功能——发包、收包、算时延、统计丢包——所以必须自己构造 ICMP 报文。常见做法是用java.net.DatagramSocket配合原始套接字或者用InetAddress拿到目标 IP 后通过DatagramPacket发送自定义字节流。但这里有个坑普通用户权限下操作系统不允许你直接发 ICMP 包。Linux 上需要root或者给 Java 进程加CAP_NET_RAW能力Windows 上需要管理员权限。这是整个课程设计里第一个卡住大多数人的地方。2.2 ICMP 回显请求报文的字节布局ICMP 报文是嵌在 IP 数据报里面的。IP 头 20 字节ICMP 头 8 字节后面跟数据部分。我们构造的时候只需要关心 ICMP 部分IP 头由操作系统内核帮我们填。ICMP 回显请求Type 8和回显应答Type 0的格式完全一样区别只在 Type 字段。8 字节的 ICMP 头结构如下偏移量长度字段名说明01 字节Type请求为 8应答为 011 字节Code恒为 022 字节Checksum整个 ICMP 报文的校验和42 字节Identifier标识符通常填进程 ID62 字节Sequence Number序列号从 1 开始递增8N 字节Data载荷通常填时间戳校验和的计算方法是把 ICMP 报文按 16 位分组所有分组做反码求和最后取反。注意计算时 Checksum 字段本身先填 0。这个算法在 Java 里用short数组循环累加就能实现但要注意 Java 没有无符号类型累加的时候要用int接最后强转回short。2.3 用 Java 构造 ICMP 包的完整代码下面这段代码是课程设计里最核心的部分直接决定你能不能发出一个合法的 ICMP 回显请求。import java.net.*; import java.nio.ByteBuffer; public class IcmpPacketBuilder { // 计算 ICMP 校验和 private static short computeChecksum(byte[] data) { int sum 0; int length data.length; int i 0; // 按 16 位一组累加 while (length 1) { sum ((data[i] 8) 0xFF00) | (data[i 1] 0xFF); i 2; length - 2; } // 如果字节数为奇数最后一个字节单独处理 if (length 1) { sum (data[i] 8) 0xFF00; } // 将高 16 位溢出加到低 16 位 while ((sum 16) ! 0) { sum (sum 0xFFFF) (sum 16); } return (short) ~sum; } // 构造 ICMP 回显请求报文 public static byte[] buildEchoRequest(int identifier, int sequence) { int dataSize 32; // 载荷 32 字节 byte[] packet new byte[8 dataSize]; packet[0] 8; // Type 8回显请求 packet[1] 0; // Code 0 // Checksum 先填 0后面计算 packet[2] 0; packet[3] 0; // Identifier 占 2 字节大端序 packet[4] (byte) ((identifier 8) 0xFF); packet[5] (byte) (identifier 0xFF); // Sequence Number 占 2 字节 packet[6] (byte) ((sequence 8) 0xFF); packet[7] (byte) (sequence 0xFF); // 填充载荷当前时间戳用于计算 RTT long timestamp System.currentTimeMillis(); ByteBuffer buffer ByteBuffer.allocate(dataSize); buffer.putLong(timestamp); // 剩余字节填固定值方便校验 for (int i 8; i dataSize; i) { buffer.put((byte) i); } System.arraycopy(buffer.array(), 0, packet, 8, dataSize); // 计算校验和并填入 short checksum computeChecksum(packet); packet[2] (byte) ((checksum 8) 0xFF); packet[3] (byte) (checksum 0xFF); return packet; } }这段代码的逻辑说明computeChecksum方法先把报文按 16 位分组累加处理奇数长度的情况然后把高 16 位的溢出折返加到低 16 位最后取反得到校验和。buildEchoRequest方法按 ICMP 头格式逐字节填充Identifier 和 Sequence 都用大端序写入载荷部分前 8 字节放当前时间戳后面填递增字节。参数identifier一般用System.currentTimeMillis() 0xFFFF或者进程 IDsequence从 1 开始每发一个包加 1。注意Java 的byte是有符号的范围 -128 到 127。写入大于 127 的值时要先跟 0xFF 做与运算再强转否则会变成负数。这是血泪经验校验和算错十有八九是这里翻的车。3. 发送与接收用 DatagramSocket 跑通第一个回显应答3.1 创建套接字并发送 ICMP 包拿到构造好的字节数组之后下一步是把它发出去。Java 里发 ICMP 包不能用DatagramSocket直接发因为DatagramSocket走的是 UDP操作系统会在 IP 头里把协议号标成 17UDP而不是 1ICMP。目标主机收到之后发现协议号不对直接丢弃你永远收不到回显应答。那怎么办常见做法有两种。第一种是用InetAddress.isReachable()做探测但前面说了拿不到 RTT。第二种是用java.net.DatagramSocket配合setSoTimeout在某些平台上操作系统会允许你发送原始 ICMP 包但这不是标准行为跨平台不可靠。真正靠谱的做法是用 JNI 调用 C 的socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)或者用Runtime.exec()直接调系统的ping命令然后解析输出。对于课程设计来说我一般推荐第三种折中方案用DatagramSocket发 UDP 包到目标主机的某个端口同时用InetAddress.isReachable()做辅助判断。但这样测的不是 ICMP报告里写清楚就行。如果指导老师要求必须实现 ICMP那就老老实实写 JNI或者用 Java 的ProcessBuilder调系统 ping。下面是用ProcessBuilder调系统 ping 并解析输出的代码这是最稳的路子import java.io.*; import java.util.regex.*; public class PingExecutor { public static void main(String[] args) throws Exception { String target www.baidu.com; // Windows 用 -n 指定次数Linux/macOS 用 -c String os System.getProperty(os.name).toLowerCase(); String countFlag os.contains(win) ? -n : -c; ProcessBuilder pb new ProcessBuilder(ping, countFlag, 4, target); pb.redirectErrorStream(true); Process process pb.start(); BufferedReader reader new BufferedReader( new InputStreamReader(process.getInputStream(), GBK)); String line; // 匹配 timexxms 或 time1ms Pattern pattern Pattern.compile(time[](\\d)ms); int received 0; long totalRtt 0; while ((line reader.readLine()) ! null) { System.out.println(line); Matcher matcher pattern.matcher(line); if (matcher.find()) { int rtt Integer.parseInt(matcher.group(1)); totalRtt rtt; received; } } process.waitFor(); System.out.println(--- 统计 ---); System.out.println(发送 4 个包收到 received 个); if (received 0) { System.out.println(平均 RTT: (totalRtt / received) ms); } } }逻辑说明ProcessBuilder启动系统 ping 命令redirectErrorStream(true)把错误流合并到标准输出避免缓冲区满了导致进程卡死。读取输出时用正则匹配timexxms或time1ms累加 RTT 并计数。参数countFlag根据操作系统自动选择Windows 是-nLinux 和 macOS 是-c。编码用 GBK 是因为 Windows 中文系统的 ping 输出是 GBK 编码用 UTF-8 读会乱码。3.2 解析回显应答与计算 RTT如果你坚持用原始套接字实现收到回显应答之后的解析逻辑是这样的先跳过 IP 头通常 20 字节但如果有选项字段可能更长然后读 ICMP 头的 Type 字段如果是 0 说明是回显应答接着读 Identifier 和 Sequence 确认是自己发的那个包最后从载荷里取出时间戳用当前时间减去时间戳就是 RTT。这里有个容易翻车的点IP 头的长度不是固定的。标准 IP 头是 20 字节但如果带了选项字段比如记录路由长度会变成 24 或 28 字节。IP 头的第一个字节低 4 位是 IHLInternet Header Length表示 IP 头有多少个 32 位字。所以实际 IP 头长度是(packet[0] 0x0F) * 4。直接写死 20 字节在某些网络环境下会解析出错。注意Linux 上普通用户没有权限创建原始套接字会抛SocketException: Permission denied。解决办法是用sudo运行或者给 Java 二进制文件加setcap cap_net_rawep。Windows 上需要以管理员身份运行 Eclipse 或者命令行。4. 避坑与排查课程设计里最容易翻车的五个地方4.1 现象程序编译通过但运行时报权限错误原因原始套接字需要系统特权。Linux 下普通用户默认没有CAP_NET_RAW能力Windows 下非管理员账户不允许创建原始套接字。解决Linux 用sudo java -cp . YourPingClass运行或者执行sudo setcap cap_net_rawep $(which java)给 Java 解释器授权。Windows 右键 Eclipse 图标选「以管理员身份运行」。如果是在 IDE 里跑注意 IDE 本身也要用管理员权限启动否则它启动的子进程继承不到权限。4.2 现象校验和算出来跟 Wireshark 抓包不一致原因Java 的byte是有符号的data[i] 8的时候如果data[i]是负数左移之后高位全是 1跟 0xFF00 做与运算结果不对。另外累加的时候用short会溢出必须用int接。解决所有字节转 int 的时候先跟 0xFF 做与运算确保变成 0 到 255 的正数。累加用int最后折返溢出位的时候用while ((sum 16) ! 0)循环处理不要只折一次。4.3 现象能收到回显应答但 RTT 是负数原因载荷里存的时间戳是发送时的时间接收时用System.currentTimeMillis()减去它。如果发送和接收用了不同的时间基准或者时间戳在字节序转换时搞反了就会算出负数。解决发送和接收都用System.currentTimeMillis()不要混用nanoTime()。字节序统一用大端序网络字节序写入用ByteBuffer.putLong()默认就是大端读取用ByteBuffer.getLong()也是大端不要手动移位。4.4 现象ping 域名通ping IP 不通原因域名解析走的是 DNS跟 ICMP 是两回事。InetAddress.getByName(www.baidu.com)返回的是解析后的 IP如果 DNS 配置有问题会抛UnknownHostException。但如果你直接 ping IP 不通说明网络层有问题可能是路由表、防火墙或者目标主机禁了 ICMP。解决先用nslookup或dig确认域名能解析出 IP再用ping直接测那个 IP。如果 IP 也不通检查本机路由表route printWindows或ip routeLinux确认默认网关存在。有些云服务器默认禁 ICMP需要在安全组里放行。4.5 现象Eclipse 里跑得好好的导出 jar 包双击运行没反应原因Eclipse 运行的时候工作目录是项目根目录导出 jar 之后双击运行工作目录变成了 jar 所在目录相对路径全变了。另外如果代码里用了System.getProperty(os.name)判断操作系统在 jar 里跑结果是一样的问题不在这。解决导出 jar 的时候在 manifest 里指定Main-Class运行时用java -jar your.jar在命令行跑这样能看到报错信息。如果双击没反应大概率是抛了异常但控制台窗口一闪而过。在代码最外层加try-catch把异常写到日志文件里或者用ProcessBuilder调 ping 的时候把错误流也读出来打印。5. 进阶技巧用 Wireshark 验证你的 ICMP 包到底长什么样课程设计报告里如果只贴代码和运行截图分数不会太高。真正能拉开差距的是抓包分析——用 Wireshark 抓下你程序发出的 ICMP 包跟标准 ping 命令发的包做对比看 Type、Code、Checksum、Identifier、Sequence 这几个字段对不对。这一步做完报告的技术深度直接上一个档次。具体操作先在 Wireshark 里选好网卡过滤器输入icmp然后运行你的 Java 程序。抓到的包如果 Type 是 8 说明是回显请求Type 是 0 说明是回显应答。点开 ICMP 详情看 Checksum 字段是不是correct如果显示incorrect说明你的校验和算错了。再看 Identifier 和 Sequence确认跟你代码里设的值一致。如果你是用ProcessBuilder调系统 ping抓到的包跟你自己构造的包格式应该一模一样因为系统 ping 也是按 RFC 792 实现的。对比的时候重点看 Data 部分系统 ping 默认填的是递增的字节序列你的程序填的是时间戳这个差异不影响功能但报告里可以写一句「载荷设计为时间戳以便于 RTT 计算」。还有一个进阶玩法把 TTL 字段也解析出来。TTL 在 IP 头里偏移量是 8。每经过一个路由器 TTL 减 1所以初始 TTL - 收到的 TTL 1就是经过的跳数。Linux 默认初始 TTL 是 64Windows 是 128。你可以在报告里加一个「路由跳数推测」的小节用收到的 TTL 反推目标主机大概经过了几跳这比单纯统计 RTT 有意思得多。最后说一个我自己的习惯每次写完网络程序先在本机ping 127.0.0.1跑通再ping局域网网关最后才ping外网域名。这样出问题的时候能快速定位是代码问题、局域网问题还是外网问题。课程设计答辩的时候老师问「你怎么保证程序是对的」你就把这个排查顺序讲出来比背概念管用。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

Office 2019 无法复制粘贴下拉单元格?试试更新 Office
Office 2019 无法复制粘贴下拉单元格?试试更新 Office

Office 2019 无法复制粘贴下拉单元格?试试更新 Office 大家好,我是杨利杰 YJlio。 在 Office 2019 Build 16.0.10417.20208 环境中,遇到 Excel 下拉单元格无法正常复制、粘贴的情况时,可以先尝试更新 Office。下面整理了三种更新… · 2026/9/24 13:38:41

PHP-Parser 0.9 升级 1.0 迁移指南:命名空间化、节点类型重命名与破坏性变更解析
PHP-Parser 0.9 升级 1.0 迁移指南:命名空间化、节点类型重命名与破坏性变更解析

示例工程数据库教程后端 【免费下载链接】sql-server-samples Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge 项目地址: https://gitcode.com/gh_mirrors… · 2026/9/24 13:38:35

Sunshine 游戏串流从零到完整上手:20 分钟搭好自托管串流主机
Sunshine 游戏串流从零到完整上手:20 分钟搭好自托管串流主机

Sunshine 游戏串流从零到完整上手:20 分钟搭好自托管串流主机 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine 是一款免费开源的自托管游戏串流服务器&#xf… · 2026/9/24 13:38:35

BlockNote 文档导出 PDF 实战:react-pdf 导出器(已弃用)完整使用指南
BlockNote 文档导出 PDF 实战:react-pdf 导出器(已弃用)完整使用指南

前端富文本UI组件AI 应用 【免费下载链接】BlockNote A React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap. 项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote 点击查看 免费下载 本指南围… · 2026/9/24 14:12:08

AMD ROCm GPU 加速计算完整指南:从0到1跑通核函数直至生产推理
AMD ROCm GPU 加速计算完整指南:从0到1跑通核函数直至生产推理

AMD ROCm GPU 加速计算完整指南:从0到1跑通核函数直至生产推理 【免费下载链接】legacy-rocm-build AMD ROCm™ Software - GitHub Home 项目地址: https://gitcode.com/GitHub_Trending/ro/legacy-rocm-build 训练任务排队等卡、HPC 作业被 CPU 拖住、单卡算… · 2026/9/24 14:12:08

Tool | UI/BI类网址收录
Tool | UI/BI类网址收录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 14:12:08

Agent 跑起来之后,模型调度才真正变难
Agent 跑起来之后,模型调度才真正变难

单轮问答的模型选型很简单:挑一个效果好的,全用它。但一旦做成 Agent——需要规划、调用工具、观察结果、再决定下一步——模型选型就变成一个动态问题。原因很直白:Agent 一次任务里会调用模型很多次,而每次调用的性质完全不同。… · 2026/9/24 14:12:08

ATECC608B安全芯片原理与I2C实战避坑指南
ATECC608B安全芯片原理与I2C实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 14:12:01

【Coze】【视频】火柴人心理学视频彩色版工作流
【Coze】【视频】火柴人心理学视频彩色版工作流

今天给大家演示一个《火柴人心理学视频彩色版》的 Coze 工作流,它融合了AI大模型文案创作、图像生成、音频合成、视频剪辑等多个模块,实现从输入心理学主题到生成完整剪辑草稿的一键式自动化流程。该工作流特别适用于创作者打造简洁、高效、可视化的心理知识短视频,最终效果… · 2026/9/24 14:11:55

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码