0

0

golang怎么实现ping

PHPz

PHPz

发布时间:2023-04-25 10:42:38

|

2224人浏览过

|

来源于php中文网

原创

golang实现ping

Ping是一个用于测试网络连接的工具,它用来测试计算机网络的连通性。Ping命令可以测通目标主机是否在线、是否可访问、以及通讯的延迟情况。本文将介绍如何使用golang编程语言实现ping工具。

一、什么是Ping

Ping是程序员、系统管理员进行网络调试和故障排查的一种必备工具。Ping是Packet Internet Groper的缩写,其作用是测试两台主机之间网络连接的连通性。Ping命令是互联网上最基本的网络服务之一,通过向目标主机发送ICMP数据包并测量响应时间来检查连接的实时性和可靠性。

二、Ping的工作原理

立即学习go语言免费学习笔记(深入)”;

Ping的原理是利用Internet控制消息协议(ICMP)的“回显请求”命令,向目标主机发送一个特殊的数据包,目标主机收到这个数据包后,会自动返回一个“回显应答”数据包给发送方,这样一来,发送方就可以通过测量数据包的往返时间来计算目标主机的响应时间和网络延迟情况。

三、实现ping

实现ping需要完成以下3个步骤:

1.构造ICMP数据包
2.发送ICMP数据包
3.解析ICMP数据包返回的响应信息

1.构造ICMP数据包

首先,我们需要构造一个ICMP数据包。根据ICMP的格式,我们可以使用Go语言自带的"icmp"包提供的结构体和函数构建一个ICMP数据包。icmp.Message和icmp.Echo指定了数据包类型和类型相关数据,icmp.Marshal取回我们构造的ICMP数据。我们可以像下面这样定义一个PingMsg:

type PingMsg struct{

icmpMessage icmp.Message
bytes []byte

}

func newEchoPingMessage(id, seq int) (*PingMsg, error){

bytes := make([]byte, 32)

//填充ICMP数据包内容

for i, _ := range bytes {
    bytes[i] = 'a' + byte(i%26)
}
icmpMessage := icmp.Message{
    Type: ipv4.ICMPTypeEcho, // ICMP类型
    Code: 0, // ICMP代码,置为0
    Checksum: 0, // 校验和,暂时置为0
    Body: &icmp.Echo{
        ID: id,
        Seq: seq,
        Data: bytes,
    },
}

//序列化ICMP数据包

b, err := icmpMessage.Marshal(nil)
if err != nil {
    return nil, err
}
return &PingMsg{
    bytes: b,
    icmpMessage: icmpMessage,
}, nil

}

2.发送ICMP数据包

接下来,我们需要使用net包提供的Conn接口发送构造好的ICMP数据包。我们可以使用net.Dial("ip4:icmp", destination)建立一个ICMP连接,使用Conn.Write(b []byte)向目标主机发送数据包,使用time.NewTicker函数来控制发送的时间间隔。

func ping(addr string) error{

conn, err := net.Dial("ip4:icmp", addr)
if err != nil {
    return err
}
defer conn.Close()
pingMsg, err := newEchoPingMessage(os.Getpid()&0xffff, 1)
if err != nil {
    return err
}
timeout := 5 * time.Second // 超时时间
ticker := time.NewTicker(time.Second) //设置1秒钟的时间间隔
defer ticker.Stop()
for {
    select {
    case <- ticker.C: // 每1秒钟发送一次ICMP数据包
        if _, err = conn.Write(pingMsg.bytes); err != nil {
            return err
        }
    case <- time.After(timeout): // 超时时间到了,抛出错误
        return errors.New("request timeout")
    }
}

}

3.解析ICMP数据包返回的响应信息

Adrenaline
Adrenaline

软件调试助手,识别和修复代码中错误

下载

最后,我们需要通过读取返回的ICMP数据包,解析出主机的响应信息。我们同样使用net包提供的Conn接口读取返回的数据包,使用icmp.ParseMessage解析数据包,并通过icmp.Message.Body.(*icmp.EchoReply)获取响应信息。

func receivePing(conn net.Conn) error{

for {
    b := make([]byte, 512)
    conn.SetReadDeadline(time.Now().Add(time.Second)) // 设置超时时间
    if n, err := conn.Read(b); err != nil {
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            continue
        }
        return err
    } else {
        recvMsg, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply, b[:n])
        if err != nil {
            return err
        }
        switch recvMsg.Type {
        case ipv4.ICMPTypeEchoReply:
            echoReply, _ := recvMsg.Body.(*icmp.EchoReply)
            log.Printf("ping %d bytes from %s: icmp_seq=%d time=%dms", len(echoReply.Data), conn.RemoteAddr().String(), echoReply.Seq, time.Since(time.Unix(0, echoReply.ArrivalTime().Nanoseconds())).Nanoseconds())
        default:
            log.Printf("unsupported ICMP message type %v (%v)", recvMsg.Type, recvMsg.Code)
        }
    }
}

}

四、完整示例

完整代码如下:

package main

import (

"errors"
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"log"
"net"
"os"
"time"

)

type PingMsg struct{

icmpMessage icmp.Message
bytes       []byte

}

func newEchoPingMessage(id, seq int) (*PingMsg, error){

bytes := make([]byte, 32)
for i, _ := range bytes {
    bytes[i] = 'a' + byte(i%26)
}
icmpMessage := icmp.Message{
    Type: ipv4.ICMPTypeEcho,
    Code: 0,
    Checksum: 0,
    Body: &icmp.Echo{
        ID: id,
        Seq: seq,
        Data: bytes,
    },
}
b, err := icmpMessage.Marshal(nil)
if err != nil {
    return nil, err
}
return &PingMsg{
    bytes: b,
    icmpMessage: icmpMessage,
}, nil

}

func ping(addr string) error{

conn, err := net.Dial("ip4:icmp", addr)
if err != nil {
    return err
}
defer conn.Close()
pingMsg, err := newEchoPingMessage(os.Getpid()&0xffff, 1)
if err != nil {
    return err
}
timeout := 5 * time.Second
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
    select {
    case <- ticker.C:
        if _, err = conn.Write(pingMsg.bytes); err != nil {
            return err
        }
    case <- time.After(timeout):
        return errors.New("request timeout")
    }
}

}

func receivePing(conn net.Conn) error{

for {
    b := make([]byte, 512)
    conn.SetReadDeadline(time.Now().Add(time.Second))
    if n, err := conn.Read(b); err != nil {
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            continue
        }
        return err
    } else {
        recvMsg, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply, b[:n])
        if err != nil {
            return err
        }
        switch recvMsg.Type {
        case ipv4.ICMPTypeEchoReply:
            echoReply, _ := recvMsg.Body.(*icmp.EchoReply)
            log.Printf("ping %d bytes from %s: icmp_seq=%d time=%dms", len(echoReply.Data), conn.RemoteAddr().String(), echoReply.Seq, time.Since(time.Unix(0, echoReply.ArrivalTime().Nanoseconds())).Nanoseconds())
        default:
            log.Printf("unsupported ICMP message type %v (%v)", recvMsg.Type, recvMsg.Code)
        }
    }
}

}

func main(){

if err := ping("www.baidu.com"); err != nil{
    log.Fatal(err)
}

}

当运行这段代码时,将会不断地发送ICMP数据包给目标主机,直到主机超时或收到回复为止。每当收到回复数据包时,程序会输出如下信息:

ping 32 bytes from 120.92.6.25: icmp_seq=0 time=29ms

这表示成功接收到了回复数据包,并显示了往返时间(return trip time)。实现Ping的过程很简单,但确实能让我们更好地理解网络通信的原理。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

22

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

99

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

132

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

15

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

61

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

63

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

33

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号