[Go]命令行工具-检测网络连通性

news/2025/3/25 17:48:04/文章来源:https://www.cnblogs.com/XY-Heruo/p/18788375

前言

实现ping、tcp端口检测、HTTP状态码检测。使用效果:

$ ./iptest tcp 192.168.0.106 9999
dial 192.168.0.106:9999 success, elapsed: 109.574125ms$ sudo ./iptest ping baidu.com
[sudo] password for test: 
来自 baidu.com 的回复: 字节=64 时间=84ms TTL=49
来自 baidu.com 的回复: 字节=64 时间=91ms TTL=49
来自 baidu.com 的回复: 字节=64 时间=105ms TTL=49
来自 baidu.com 的回复: 字节=64 时间=113ms TTL=49$ ./iptest http 192.168.0.106  -p 9999 -s http
Connected to http://192.168.0.106:9999, response code: 307

准备

go mod init iptest
cobra-cli init
cobra-cli add ping
cobra-cli add tcp
cobra-cli add http

示例代码

  • cmd/ping.go
package cmdimport ("bytes""encoding/binary""fmt""math""net""time""github.com/spf13/cobra"
)// pingCmd represents the ping command
var pingCmd = &cobra.Command{Use:     "ping",Short:   "向主机发起ping测试",Long:    `向主机发起ICMP协议的ping请求. Linux系统下运行需要root权限`,Example: `./iptest ping baidu.com`,Run: func(cmd *cobra.Command, args []string) {// fmt.Println("ping called")if len(args) > 0 {host := args[0]pingMain(host, count)} else {fmt.Println("未检测到参数传入")}},
}var count intfunc init() {rootCmd.AddCommand(pingCmd)pingCmd.Flags().IntVarP(&count, "count", "c", 4, "ping次数")
}type icmpStruct struct {Type        uint8Code        uint8CheckSum    uint16Identifier  uint16SequenceNum uint16
}func pingMain(host string, count int) {// laddr := net.IPAddr{IP: net.ParseIP("ip")}conn, err := net.DialTimeout("ip:icmp", host, 2*time.Second)if err != nil {fmt.Printf("Connecting to %s failed\n", host)return}defer conn.Close()icmp := icmpStruct{Type:        8,Code:        0,CheckSum:    0,Identifier:  1,SequenceNum: 1,}var buffer bytes.Bufferbinary.Write(&buffer, binary.BigEndian, icmp)data := make([]byte, 64)buffer.Write(data)data = buffer.Bytes()var SuccessTimes int // 成功次数var FailTimes int    // 失败次数var minTime int = int(math.MaxInt32)var maxTime intvar totalTime intfor i := 0; i < count; i++ {icmp.SequenceNum = uint16(1)data[2] = byte(0)data[3] = byte(0)data[6] = byte(icmp.SequenceNum >> 8)data[7] = byte(icmp.SequenceNum)icmp.CheckSum = checkSum(data)data[2] = byte(icmp.CheckSum >> 8)data[3] = byte(icmp.CheckSum)// 开始时间t1 := time.Now()conn.SetDeadline(t1.Add(2 * time.Second))_, err := conn.Write(data)if err != nil {// log.Fatal(err)fmt.Println(err)return}buf := make([]byte, 65535)n, err := conn.Read(buf)if err != nil {fmt.Println("请求超时。")FailTimes++continue}et := int(time.Since(t1) / 1000000)if minTime > et {minTime = et}if maxTime < et {maxTime = et}totalTime += etfmt.Printf("来自 %s 的回复: 字节=%d 时间=%dms TTL=%d\n", host, len(buf[28:n]), et, buf[8])SuccessTimes++time.Sleep(1 * time.Second)}
}/*
计算校验和
1. 将ICMP头部内容中的校验内容的值置为0
2.
*/
func checkSum(data []byte) uint16 {var sum uint32var length = len(data)var index intfor length > 1 { // 溢出部分直接去除sum += uint32(data[index])<<8 + uint32(data[index+1])index += 2length -= 2}if length == 1 {sum += uint32(data[index])}// CheckSum的值是16位,计算是将高16位加低16位,得到的结果进行重复以该方式进行计算,直到高16位为0/*sum的最大情况是:ffffffff第一次高16位+低16位:ffff + ffff = 1fffe第二次高16位+低16位:0001 + fffe = ffff即推出一个结论,只要第一次高16位+低16位的结果,再进行之前的计算结果用到高16位+低16位,即可处理溢出情况*/sum = uint32(sum>>16) + uint32(sum)sum = uint32(sum>>16) + uint32(sum)return uint16(^sum)
}
  • cmd/tcp.go
package cmdimport ("fmt""net""os""strconv""time""github.com/spf13/cobra"
)// tcpCmd represents the tcp command
var tcpCmd = &cobra.Command{Use:   "tcp",Short: "检测tcp端口是否连通",Long:  `检测远端tcp端口是否连通`,Example: `./iptest tcp 192.168.0.106 9999`,Run: func(cmd *cobra.Command, args []string) {if len(args) > 0 {host := args[0]portStr := args[1]port, err := strconv.Atoi(portStr)if err != nil {fmt.Printf("%s 非有效数值\n", portStr)return}tcpMain(host, port)} else {fmt.Println("未检测到参数传入")}},
}func init() {rootCmd.AddCommand(tcpCmd)
}func tcpMain(host string, port int) {start := time.Now()conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 2*time.Second)if err != nil {if os.IsTimeout(err) {fmt.Printf("Connecting to %s:%d timeout\n", host, port)return} else {fmt.Printf("Connecting to %s:%d failed\n", host, port)return}}defer conn.Close()elapsed := time.Since(start)if conn != nil {fmt.Printf("dial %s:%d success, elapsed: %v\n", host, port, elapsed)} else {fmt.Printf("dial %s:%d failed\n", host, port)}
}
  • cmd/http.go
package cmdimport ("fmt""net/http""os""time""github.com/spf13/cobra"
)// httpCmd represents the http command
var httpCmd = &cobra.Command{Use:   "http",Short: "检测远端http是否连通",Long:  `通过发起HEAD请求, 根据状态码判断是否连通`,Example: `# 检测 https://example.com:443./iptest http example.com# 检测 http://example.com:80./iptest http -s http -p 80 example.com`,Run: func(cmd *cobra.Command, args []string) {if len(args) > 0 {host := args[0]httpMain(host, port)} else {fmt.Println("未检测到参数传入")}},
}
var (schema stringport   int
)func init() {rootCmd.AddCommand(httpCmd)httpCmd.Flags().StringVarP(&schema, "schema", "s", "https", "schema")httpCmd.Flags().IntVarP(&port, "port", "p", 443, "port")
}func httpMain(host string, port int) {if schema != "http" && schema != "https" {fmt.Println("schema must be http or https")return}var dest string = fmt.Sprintf("%s://%s:%d", schema, host, port)client := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error {return http.ErrUseLastResponse},Timeout: time.Second * 2,}resp, err := client.Head(dest)if err != nil {if os.IsTimeout(err) {fmt.Printf("Connecting to %s://%s:%d timeout\n", schema, host, port)return} else {fmt.Printf("Connecting to %s://%s:%d failed\n", schema, host, port)return}}fmt.Printf("Connected to %s://%s:%d, response code: %d\n", schema, host, port, resp.StatusCode)
}

参考

  • 博客园 - 使用go实现一个ping程序
  • 简书 - Go语言实现ping命令

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编译原理第五次作业

2.2.1 1)S-> S S *-> S S + S *->a S + S *->a a + S *->a a + a * 2)3)L={由多个a,加号,乘号组成的后缀表达式} 2.2.2 1)L={0^n 1^n | n>=1} 2)L={由多个a,加号,减号组成的前缀表达式} 3)L={ε或任意排列,嵌套的括号} 4)L={ε或包含相同数量a,b的字符…

XN2025 集训记录 D2

我好想你们啊 . 我怀念高一啊 . 至少还有理由放任自己开心不是吗 .XN2025 集训记录 D2 又是摆烂的一天 , 感觉打模拟赛时候的自己和改题时的自己完全不是一个人 . 不过往好了想 , 至少足够的模拟赛量 , 意味着我的高效率时间虽然不多 , 但是还有 . 买了个usb转网线 , 破费 39.9…

基于对偶二次曲线的快速椭圆检测

利用对偶二次曲线可精确求解椭圆圆心坐标。1、对偶二次曲线原理 二次曲线也称圆锥曲线,其几何定义是一个平面与两个顶点相对的圆锥相交所产生的交线。通常二次曲线指的是点二次曲线,它是定义在曲线点上的方程。而在射影几何中,齐次点和齐次线存在着可以互换的二元关系,因此…

【程设の旅】Python速通作业三

这节课老师讲了Python的面向对象部分 速度比较快 但是结合前面cpp的大部分知识可以弄懂 最后一道题估计是py特性了 可以理解但是那两个函数不知道是什么鬼 01:运算符的实现 描述 程序填空class A:def __init__(self,x):self.x = x // 在此处补充你的代码 a,b,c = map(int,input…

C/C++开发文档和常用的输入方式汇总

前几天复习的几种输入方式和帮助文档C/C++开发文档获取 之前下载过应该开发文档,今天push到了Gitee上了。可以随时获取,链接字符串操作 C 字符串 | 菜鸟教程 输入输出【包含字符串】 C 输入 & 输出 | 菜鸟教程 #include<stdio.h> int main() {char s[20];int i = 0…

Eino overview

一段话总结 Eino 是基于Golang的大模型应用开发框架,通过组件抽象(如ChatModel、Tool、Retriever)和图编排能力(Chain/Graph/Workflow)简化LLM应用开发。其核心优势包括类型安全的流处理、并发管理、切面注入以及开箱即用的最佳实践,支持构建复杂智能体(如ReAct)和多模…

llm 量化技术综述

综述: LLM 量化 1. Intro 低比特量化主要是减少tensor的bit-width,可以有效减少内存以及计算需求;主要可以压缩权重, 激活值, 和梯度,使得可以在受限资源的设备上使用。 2. 低比特LLM的基础 在这一届,我们主要引入从以下三个方面讨论:low-bit 数值格式 量化粒度 动态或者静…

Top 出海 AI 公司招技术!HIX.AI Pollo.ai | 深圳

HIX.AI & Pollo.ai 招聘高级海外 AI 产品经理 (25-45K) 岗位职责:负责Web 端海外 AI 产品的规划与策划,负责产品需求分析及原型设计,并制定方案推动产品研发落地; 进行产品/竞品调研,了解用户需求,分析、发现需求本质,并给出对应的解决方案; 有效对接开发、测试、运…

2、切片

一:字符串的下标(索引)--重点 ​ Ⅰ:字符串的特性,被称为下标或者 sequence(序列) ​ Ⅱ:一个序列。若干元素组成 ​ Ⅲ:字符串的下标从0开始》标记每个元素的位置,用来获取元素》从左到右,从0开始> a[0],a[1] ,a[3]》可以用正数表示,也可以用负数表示》最…

WEBGL 学习使用代码

目录杂七杂八第一节 绘制出了一个点第二节 动态传递点数据第三节 缓冲区和画线第四节 彩色线段第五节 单个 buffer 渲染颜色第六节 抽离代码 & 画彩色三角形第七节 图元的七种绘制方式第八节 uniform 传值变换数据第九节 旋转矩阵三角函数矩阵的计算推导代码实现第十节 线框…

Kettle 版本这么多,到底该怎么选?

Kettle(Pentaho Data Integration)作为一款功能强大的开源 ETL(Extract, Transform, Load,即数据抽取、转换和加载)工具,拥有众多版本,这让许多用户在选择时犯了难。 1、提出问题 经常有群友提出使用kettle版本的问题,如下图所示:2、kettle版本 有许多的的历史版本,…