1. 程式人生 > >【go語言 socket程式設計系列】IPAddr型別及ResolveIPAddr方法

【go語言 socket程式設計系列】IPAddr型別及ResolveIPAddr方法

【型別定義】

IPAddr型別本質上是一個IP型別,原始碼定義檔案:golang/src/pkg/net/iprawsock.go

常用方法會返回一個*IPAddr的資料。

package net

// IPAddr represents the address of an IP end point.
type IPAddr struct {
        IP   IP
        Zone string // IPv6 scoped addressing zone
}

【net.ResolveIPAddr 方法】

func ResolveIPAddr(net, addr string) (*IPAddr, error) 

將addr解析成ip,返回一個*IPAddr資料

net 引數為 "ip", "ip4" 或者為"ip6",net 為空這預設 ip

原始碼如下

// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
        if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
                net = "ip"
        }   
        afnet, _, err := parseNetwork(net)
        if err != nil {
                return nil, err 
        }   
        switch afnet {
        case "ip", "ip4", "ip6":
        default:
                return nil, UnknownNetworkError(net)
        }   
        a, err := resolveInternetAddr(afnet, addr, noDeadline)
        if err != nil {
                return nil, err 
        }   
        return a.toAddr().(*IPAddr), nil 
}

主要呼叫到以下兩個函式

     1、parseNetwork(net)

     2、resolveInternetAddr(afnet, addr, noDeadline)

parseNetwork 函式定義如下,在dial.go檔案中。

會呼叫lookupProtocol(protostr)方法 從unix作業系統中的/etc/protocols檔案中查詢協議名詞,並返回相應的協議號

func parseNetwork(net string) (afnet string, proto int, err error) {
        i := last(net, ':')
        if i < 0 { // no colon
                switch net {
                case "tcp", "tcp4", "tcp6":
                case "udp", "udp4", "udp6":
                case "ip", "ip4", "ip6":
                case "unix", "unixgram", "unixpacket":
                default:
                        return "", 0, UnknownNetworkError(net)
                }
                return net, 0, nil
        }
        afnet = net[:i]
        switch afnet {
        case "ip", "ip4", "ip6":
                protostr := net[i+1:]
                proto, i, ok := dtoi(protostr, 0)
                if !ok || i != len(protostr) {
                        proto, err = lookupProtocol(protostr)
                        if err != nil {
                                return "", 0, err
                        }
                }
                return afnet, proto, nil
        }
        return "", 0, UnknownNetworkError(net)
}
                         

 resolveInternetAddr函式定義如下,在 ipsock.go檔案中

 // resolveInternetAddr resolves addr that is either a literal IP
 // address or a DNS name and returns an internet protocol family
 // address. It returns a list that contains a pair of different
 // address family addresses when addr is a DNS name and the name has
 // mutiple address family records. The result contains at least one
 // address when error is nil.
func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
        var (
                err              error
                host, port, zone string
                portnum          int
        )
        switch net {
        case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
                if addr != "" {
                        if host, port, err = SplitHostPort(addr); err != nil {
                                return nil, err
                        }
                        if portnum, err = parsePort(net, port); err != nil {
                                return nil, err
                        }
                }
        case "ip", "ip4", "ip6":
                if addr != "" {
                        host = addr
                }
        default:
                return nil, UnknownNetworkError(net)
        }
        inetaddr := func(ip IP) netaddr {
                switch net {
                case "tcp", "tcp4", "tcp6":
                        return &TCPAddr{IP: ip, Port: portnum, Zone: zone}
                case "udp", "udp4", "udp6":
                        return &UDPAddr{IP: ip, Port: portnum, Zone: zone}
                case "ip", "ip4", "ip6":
                        return &IPAddr{IP: ip, Zone: zone}
                default:
                        panic("unexpected network: " + net)
                }
        }
        if host == "" {
                return inetaddr(nil), nil
        }
        // Try as a literal IP address.
        var ip IP
        if ip = parseIPv4(host); ip != nil {
                return inetaddr(ip), nil
        }
        if ip, zone = parseIPv6(host, true); ip != nil {
                return inetaddr(ip), nil
        }
        // Try as a DNS name.
        host, zone = splitHostZone(host)
        ips, err := lookupIPDeadline(host, deadline)
      if err != nil {
                return nil, err
        }
        var filter func(IP) IP
        if net != "" && net[len(net)-1] == '4' {
                filter = ipv4only
        }
        if net != "" && net[len(net)-1] == '6' || zone != "" {
                filter = ipv6only
        }
        return firstFavoriteAddr(filter, ips, inetaddr)
}

【程式碼實現】

package main

import (
	"fmt"
	"net"
	"os"
)

func main() {
	mydns := "www.csdn.net"
	addr, err := net.ResolveIPAddr("ip", mydns)
	checkError(err)

	fmt.Println("dns is:", mydns)
	fmt.Println("ip is:", addr.String())

}

func checkError(err error) {
	if err != nil {
		fmt.Println("Fatal err!", err.Error())
		os.Exit(1)
	}
}

編譯執行

$./l_ResolveIPAddr 
dns is: www.csdn.net
ip is: 47.95.164.112
$