【类型定义】
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)
}
【代码实现】
net.ResolveIPAddr方法调用的代码实现
package main
import (
"fmt"
"net"
"os"
)
func main() {
mydns := "www.youkuaiyun.com"
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.youkuaiyun.com
ip is: 47.95.164.112
$