ホームページ バックエンド開発 Golang golangでpingを実装する方法

golangでpingを実装する方法

Apr 25, 2023 am 10:42 AM

golang は ping を実装します

Ping はネットワーク接続のテストに使用されるツールで、コンピューター ネットワークの接続性をテストするために使用されます。 Ping コマンドは、ターゲット ホストがオンラインか、アクセス可能か、および通信遅延をテストできます。この記事では、プログラミング言語 golang を使用して ping ツールを実装する方法を紹介します。

1. Ping とは

Ping は、プログラマーやシステム管理者がネットワークのデバッグやトラブルシューティングを行うために不可欠なツールです。 Ping は Packet Internet Groper の略語で、その機能は 2 つのホスト間のネットワーク接続の接続性をテストすることです。 Ping コマンドは、インターネット上の最も基本的なネットワーク サービスの 1 つで、ICMP パケットをターゲット ホストに送信し、応答時間を測定することで、接続のリアルタイム性と信頼性をチェックします。

2. Ping の仕組み

Ping の原理は、インターネット制御メッセージ プロトコル (ICMP) の「echo request」コマンドを使用して、特別なデータ パケットをターゲット ホストに送信することです。このパケットを受信すると、自動的に「エコー応答」パケットが送信者に返され、送信者はパケットの往復時間を測定することで、対象ホストの応答時間やネットワーク遅延を計算することができます。

3. 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 パケットを送信する

#次に、構築された ICMP パケットを送信するには、net パッケージによって提供される Conn インターフェイスを使用する必要があります。 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 パケットによって返された応答情報を解析します

最後に、次のことを行う必要があります。 read 返された ICMP パケットを取得し、ホストの応答情報を解析します。また、net パッケージによって提供される Conn インターフェイスを使用して、返されたデータ パケットを読み取り、icmp.ParseMessage を使用してデータ パケットを解析し、icmp.Message.Body.(*icmp.EchoReply) を通じて応答情報を取得します。

func acceptPing(conn net.Conn) エラー{

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)
        }
    }
}
ログイン後にコピー
}

4. 完全な例

完全なコードは次のとおりです:

パッケージ 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, エラー){

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) エラー{

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 acceptPing(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

これは、応答パケットが正常に受信されたことを意味します。そして復路の所要時間が表示されます。 Ping の実装プロセスは非常に単純ですが、ネットワーク通信の原理をより深く理解できるようになります。

以上がgolangでpingを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Debian OpenSSLの脆弱性は何ですか Debian OpenSSLの脆弱性は何ですか Apr 02, 2025 am 07:30 AM

OpenSSLは、安全な通信で広く使用されているオープンソースライブラリとして、暗号化アルゴリズム、キー、証明書管理機能を提供します。ただし、その歴史的バージョンにはいくつかの既知のセキュリティの脆弱性があり、その一部は非常に有害です。この記事では、Debian SystemsのOpenSSLの共通の脆弱性と対応測定に焦点を当てます。 Debianopensslの既知の脆弱性:OpenSSLは、次のようないくつかの深刻な脆弱性を経験しています。攻撃者は、この脆弱性を、暗号化キーなどを含む、サーバー上の不正な読み取りの敏感な情報に使用できます。

PPROFツールを使用してGOパフォーマンスを分析しますか? PPROFツールを使用してGOパフォーマンスを分析しますか? Mar 21, 2025 pm 06:37 PM

この記事では、プロファイリングの有効化、データの収集、CPUやメモリの問題などの一般的なボトルネックの識別など、GOパフォーマンスを分析するためにPPROFツールを使用する方法について説明します。

Goでユニットテストをどのように書きますか? Goでユニットテストをどのように書きますか? Mar 21, 2025 pm 06:34 PM

この記事では、GOでユニットテストを書くことで、ベストプラクティス、モッキングテクニック、効率的なテスト管理のためのツールについて説明します。

GOの浮動小数点番号操作に使用されるライブラリは何ですか? GOの浮動小数点番号操作に使用されるライブラリは何ですか? Apr 02, 2025 pm 02:06 PM

GO言語の浮動小数点数操作に使用されるライブラリは、精度を確保する方法を紹介します...

Go's Crawler Collyのキュースレッドの問題は何ですか? Go's Crawler Collyのキュースレッドの問題は何ですか? Apr 02, 2025 pm 02:09 PM

Go Crawler Collyのキュースレッドの問題は、Go言語でColly Crawler Libraryを使用する問題を調査します。 �...

フロントエンドからバックエンドの開発に変身すると、JavaやGolangを学ぶことはより有望ですか? フロントエンドからバックエンドの開発に変身すると、JavaやGolangを学ぶことはより有望ですか? Apr 02, 2025 am 09:12 AM

バックエンド学習パス:フロントエンドからバックエンドへの探査の旅は、フロントエンド開発から変わるバックエンド初心者として、すでにNodeJSの基盤を持っています...

go.modファイルで依存関係をどのように指定しますか? go.modファイルで依存関係をどのように指定しますか? Mar 27, 2025 pm 07:14 PM

この記事では、go.modを介してGOモジュールの依存関係の管理、仕様、更新、競合解決をカバーすることについて説明します。セマンティックバージョンや定期的な更新などのベストプラクティスを強調しています。

GOでテーブル駆動型テストをどのように使用しますか? GOでテーブル駆動型テストをどのように使用しますか? Mar 21, 2025 pm 06:35 PM

この記事では、GOでテーブル駆動型のテストを使用して説明します。これは、テストのテーブルを使用して複数の入力と結果を持つ関数をテストする方法です。読みやすさの向上、重複の減少、スケーラビリティ、一貫性、および

See all articles