Go实现ping的3种方式

文章介绍了在容器云项目背景下,基于Go语言实现ping功能的三种方法。第一种方法直接用Go实现ping原理,但源IP不可变。第二种涉及远程登录到目标机器再ping,虽可行但存在安全隐患。最终采用第三种方案,通过在每个pod中引入故障排查容器,直接使用Go调用相关API来实现ping操作,确保安全性与效率。
摘要由CSDN通过智能技术生成

版权声明:本文为博主原创文章,博客地址:
https://blog.csdn.net/zxy_666/article/details/79958948,未经博主允许不得转载。


背景

公司容器云项目需在平台界面上提供一个ping工具,实现从任何pod内ping指定IP.

背景说明:

· 容器云项目
容器云项目是基于kubernetes(简称k8s)集群搭建的应用容器管理平台。集群中的节点是虚拟机或物理机,节点分为master节点和node节点(worker节点)。node节点上运行着pod(k8s集群的最小工作单元),pod中运行着容器,数量随意,但公司的项目里一个pod只运行一个容器。其中,容器是应用提供服务的载体,应用打成镜像后用于创建相应的容器。
每个节点都有各自的IP,每个pod也有他们的IP,通常在集群搭建时,给pod分配指定网段内的IP,由flannel实现集群间网络的通信,flannel保证集群中的每个pod都被分配不同的IP,避免了网络冲突。

· ping需求分析
集群外可以ping通集群的节点IP,却ping不通集群内的ip,如pod的ip。但是应用方pod提供的服务会出现访问不了的情况,运维人员需登录到集群上查看响应pod的网络情况。为了解放运维人员的部分劳动力,故有此需求,希望在容器云平台界面直接提供一个ping工具,让使用者可以直接从每个pod实例发出ping命令,ping目标的IP由使用者提供,发出ping请求的源pod的ip就是该pod在集群中创建时被分配的ip,前端可获取得到。

实现历程:

依次尝试了3种方案,直到第三种才实现了需求。

  • 用go实现ping原理
  • (使用go提供的终端登录,在目标终端直接发出ping命令)/(在本机直接发出ping命令)
  • 在每个pod内引入故障诊断容器

方案一 :实现ping的原理


方案:
用go实现ping的原理,参数是ping的目标IP和ping请求次数。限制是:该方案ping的源IP无法更改,默认就是发出ping操作的机器IP

实现:

注:本程序(ICMP协议)需要root权限才可执行,启动需要sudo权限

package main

import (
    "net"
    "time"
    "fmt"
    "strconv"
    "os"
)

type PingOption struct{
    Count int
    Size int
    Timeout int64
    Nerverstop bool
}

func NewPingOption()*PingOption{
    return &PingOption{
        Count:4,
        Size:32,
        Timeout:1000,
        Nerverstop:false,
    }
}

func main(){
    //argsmap:=map[string]interface{}{}
    //ping3("www.yeepay.com",argsmap)//10.151.30.227  不存在:67.4.3.2(现在又存在了)  公网IP:63.142.250.4(通)
    argsmap:=map[string]interface{}{}
     p:=NewPingOption()
     p.ping3("www.baidu.com",argsmap)
}

//ping连接用的协议是ICMP,原理:
//Ping的基本原理是发送和接受ICMP请求回显报文。接收方将报文原封不动的返回发送方,发送方校验报文,校验成功则表示ping通。
//一台主机向一个节点发送一个类型字段值为8的ICMP报文,如果途中没有异常(如果没有被路由丢弃,目标不回应ICMP或者传输失败),
//则目标返回类型字段值为0的ICMP报文,说明这台主机可达
func (p *PingOption)ping3(host string, args map[string]interface{}) {
    //要发送的回显请求数
    var count int = 4
    //要发送缓冲区大小,单位:字节
    var size int = 32
    //等待每次回复的超时时间(毫秒)
    var timeout int64 = 1000
    //Ping 指定的主机,直到停止
    var neverstop bool = false
    fmt.Println(args,"args")
    if len(args)!=0{
        count = args["n"].(int)
        size = args["l"].(int)
        timeout = args["w"].(int64)
        neverstop = args["t"].(bool)
    }

    //查找规范的dns主机名字  eg.www.baidu.com->www.a.shifen.com
    cname, _ := net.LookupCNAME(host)
    starttime := time.Now()
    //此处的链接conn只是为了获得ip := conn.RemoteAddr(),显示出来,因为后面每次连接都会重新获取conn,todo 但是每次重新获取的conn,其连接的ip保证一致么?
    conn, err := net.DialTimeout("ip4:icmp", host, time.Duration(timeout*1000*1000))
    //每个域名可能对应多个ip,但实际连接时,请求只会转发到某一个上,故需要获取实际连接的远程ip,才能知道实际ping的机器是哪台
//  ip := conn.RemoteAddr()
//  fmt.Println("正在 Ping " + cname + " [" + ip.String() + "] 具有 32 字节的数据:")

    var seq int16 = 1
    id0, id1 := genidentifier3(host)
    //ICMP报头的长度至少8字节,如果报文包含数据部分则大于8字节。
    //ping命令包含"请求"(Echo Request,报头类型是8)和"应答"(Echo Reply,类型是0)2个部分,由ICMP报头的类型决定
    const ECHO_REQUEST_HEAD_LEN = 8

    //记录发送次数
    sendN := 0
    //成功应答次数
    recvN := 0
    //记录失败请求数
    lostN := 0
    //所有请求中应答时间最短的一个
    shortT := -1
    //所有请求中应答时间最长的一个
    longT := -1
    //所有请求的应答时间和
    sumT := 0

    for count > 0 || neverstop {
        sendN++
        //ICMP报文长度,报头8字节,数据部分32字节
        var msg []byte = make([]byte, size+ECHO_REQUEST_HEAD_LEN)
        //第一个字节表示报文类型,8表示回显请求
        msg[0] = 8                        // echo
        //ping的请求和应答,该code都为0
        msg[1] = 0                        // code 0
        //校验码占2字节
        msg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值