golang implémente ping
Ping est un outil pour tester les connexions réseau. Il est utilisé pour tester la connectivité des réseaux informatiques. La commande Ping peut tester si l'hôte cible est en ligne, accessible et le délai de communication. Cet article explique comment implémenter l'outil ping à l'aide du langage de programmation Golang.
1. Qu'est-ce que Ping
Ping est un outil essentiel permettant aux programmeurs et aux administrateurs système d'effectuer le débogage et le dépannage du réseau. Ping est l'abréviation de Packet Internet Groper, et sa fonction est de tester la connectivité de la connexion réseau entre deux hôtes. La commande Ping est l'un des services réseau les plus basiques sur Internet. Elle vérifie le temps réel et la fiabilité de la connexion en envoyant des paquets ICMP à l'hôte cible et en mesurant le temps de réponse.
2. Comment fonctionne Ping
Le principe de Ping est d'utiliser la commande "echo request" du protocole ICMP (Internet Control Message Protocol) pour envoyer un paquet de données spécial à l'hôte cible. L'hôte renvoie automatiquement un paquet de « réponse d'écho » à l'expéditeur afin que celui-ci puisse calculer le temps de réponse de l'hôte cible et la latence du réseau en mesurant le temps d'aller-retour du paquet.
3. Implémentation de ping
Pour implémenter ping, vous devez effectuer les 3 étapes suivantes :
1. Construire des paquets de données ICMP
2. Envoyer des paquets de données ICMP
3. Analyser les informations de réponse renvoyées par les paquets de données ICMP. 1. Construire un paquet de données ICMP
Tout d'abord, nous devons construire un paquet ICMP. Selon le format ICMP, nous pouvons utiliser les structures et fonctions fournies par le package « icmp » fourni avec le langage Go pour construire un paquet de données ICMP. icmp.Message et icmp.Echo spécifient le type de paquet et les données liées au type, et icmp.Marshal récupère les données ICMP que nous avons construites. Nous pouvons définir un PingMsg comme suit :
type PingMsg struct{
icmpMessage icmp.Message bytes []byte
}
func newEchoPingMessage(id, seq int) (*PingMsg, error){
bytes := make([]byte, 32)
//Remplir le contenu du paquet 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, }, }
/ / Sérialiser les paquets ICMP
b, err := icmpMessage.Marshal(nil) if err != nil { return nil, err } return &PingMsg{ bytes: b, icmpMessage: icmpMessage, }, nil
}
2. Envoyer des paquets ICMP
Ensuite, nous devons utiliser l'interface Conn fournie par le package net pour envoyer les paquets ICMP construits. Nous pouvons utiliser net.Dial("ip4:icmp", destination) pour établir une connexion ICMP, utiliser Conn.Write(b []byte) pour envoyer des paquets de données à l'hôte cible et utiliser la fonction time.NewTicker pour contrôler le intervalle de temps d'envoi.
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. Analyser les informations de réponse renvoyées par le paquet ICMP
Enfin, nous devons analyser les informations de réponse de l'hôte en lisant le paquet ICMP renvoyé. Nous utilisons également l'interface Conn fournie par le package net pour lire le paquet de données renvoyé, utilisons icmp.ParseMessage pour analyser le paquet de données et obtenons les informations de réponse via icmp.Message.Body.(*icmp.EchoReply). Erreur de réception CFunc (Con NET.CONN) {
Rreeee}
4. Exemples complets
Code complet comme suit :
Package Main
import (
Rreeee)
Type Pingmsg Strut {
Rreeee}
func newEchoPingMessage(id, seq int) (*PingMsg, erreur){
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) error{
"errors" "fmt" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" "log" "net" "os" "time"
}
func containPing(conn net.Conn) error{
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
}
Lorsque ce code est exécuté, les paquets ICMP seront envoyés en continu à l'hôte cible jusqu'à ce que l'hôte expire ou reçoive une réponse. Chaque fois qu'un paquet de réponse est reçu, le programme affichera les informations suivantes :
ping 32 octets de 120.92.6.25 : icmp_seq=0 time=29ms
Cela signifie que le paquet de réponse est reçu avec succès et que le temps aller-retour est affiché . temps). Le processus de mise en œuvre de Ping est très simple, mais il permet de mieux comprendre les principes de la communication réseau.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!