golang implementiert Ping
Ping ist ein Tool zum Testen von Netzwerkverbindungen. Es wird verwendet, um die Konnektivität von Computernetzwerken zu testen. Der Ping-Befehl kann testen, ob der Zielhost online und erreichbar ist und wie hoch die Kommunikationsverzögerung ist. In diesem Artikel wird erläutert, wie Sie das Ping-Tool mithilfe der Programmiersprache Golang implementieren.
1. Was ist Ping? Ping ist ein unverzichtbares Tool für Programmierer und Systemadministratoren zur Fehlerbehebung und Fehlerbehebung im Netzwerk. Ping ist die Abkürzung für Packet Internet Groper und dient dazu, die Konnektivität der Netzwerkverbindung zwischen zwei Hosts zu testen. Der Ping-Befehl ist einer der grundlegendsten Netzwerkdienste im Internet. Er überprüft die Echtzeit und Zuverlässigkeit der Verbindung, indem er ICMP-Pakete an den Zielhost sendet und die Antwortzeit misst.
2. Wie Ping funktioniert
Das Prinzip von Ping besteht darin, den „Echo Request“-Befehl des Internet Control Message Protocol (ICMP) zu verwenden, um nach dem Empfang des Datenpakets ein spezielles Datenpaket an den Zielhost zu senden Der Host sendet automatisch ein „Echo-Antwort“-Paket an den Absender zurück, sodass der Absender die Antwortzeit und Netzwerklatenz des Zielhosts berechnen kann, indem er die Umlaufzeit des Pakets misst.
3. Ping implementieren
Um Ping zu implementieren, müssen Sie die folgenden 3 Schritte ausführen:
1. ICMP-Datenpakete erstellen
1. ICMP-Datenpaket erstellen
Zuerst müssen wir ein ICMP-Paket erstellen. Gemäß dem ICMP-Format können wir die Strukturen und Funktionen des mit der Go-Sprache gelieferten Pakets „icmp“ verwenden, um ein ICMP-Datenpaket zu erstellen. icmp.Message und icmp.Echo geben den Pakettyp und die typbezogenen Daten an, und icmp.Marshal ruft die von uns erstellten ICMP-Daten ab. Wir können eine PingMsg wie folgt definieren:
type PingMsg struct{
icmpMessage icmp.Message bytes []byte
}
func newEchoPingMessage(id, seq int) (*PingMsg, error){
bytes := make([]byte, 32)
//Füllen Sie den ICMP-Paketinhalt
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-Pakete serialisieren
b, err := icmpMessage.Marshal(nil) if err != nil { return nil, err } return &PingMsg{ bytes: b, icmpMessage: icmpMessage, }, nil
}
2. ICMP-Pakete senden
Als nächstes müssen wir die vom Netzpaket bereitgestellte Conn-Schnittstelle verwenden, um die erstellten ICMP-Pakete zu senden. Wir können net.Dial("ip4:icmp", Destination) verwenden, um eine ICMP-Verbindung herzustellen, Conn.Write(b []byte) verwenden, um Datenpakete an den Zielhost zu senden, und die Funktion time.NewTicker verwenden, um das zu steuern Sendezeitintervall.
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. Die vom ICMP-Paket zurückgegebenen Antwortinformationen analysieren
Zuletzt müssen wir die Antwortinformationen des Hosts analysieren, indem wir das zurückgegebene ICMP-Paket lesen. Wir verwenden auch die vom Net-Paket bereitgestellte Conn-Schnittstelle, um das zurückgegebene Datenpaket zu lesen, verwenden icmp.ParseMessage, um das Datenpaket zu analysieren, und erhalten die Antwortinformationen über icmp.Message.Body.(*icmp.EchoReply). CFunc-Empfangsfehler (Con NET.CONN) {
Rreeee}
4. Vollständige Beispiele
Vollständiger Code wie folgt:
Package Main
import (
Rreeee)
Type Pingmsg Strut {
Rreeee}
func newEchoPingMessage(id, seq int) (*PingMsg, Fehler){
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 ping(addr string) Fehler{
"errors" "fmt" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" "log" "net" "os" "time"
}
funcempfangenPing(conn net.Conn) Fehler{
icmpMessage icmp.Message bytes []byte
}
func main(){
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
}
Wenn dieser Code ausgeführt wird, werden ICMP-Pakete kontinuierlich an den Zielhost gesendet, bis der Host eine Zeitüberschreitung erfährt oder eine Antwort erhält. Immer wenn ein Antwortpaket empfangen wird, gibt das Programm die folgende Information aus:
ping 32 bytes from 120.92.6.25: icmp_seq=0 time=29ms
Dies bedeutet, dass das Antwortpaket erfolgreich empfangen wurde und die Roundtrip-Zeit angezeigt wird . Zeit). Der Prozess der Ping-Implementierung ist sehr einfach, ermöglicht uns jedoch ein besseres Verständnis der Prinzipien der Netzwerkkommunikation.
Das obige ist der detaillierte Inhalt vonSo implementieren Sie Ping in Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!