32
Golang 网络编程丝绸之路 - TCP/UDP 地址解析
source link: https://www.tuicool.com/articles/neq6v2n
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
TL;DR在使用 Golang 编写 TCP/UDP socket 的时候,第一步做的就是地址解析。
- func ResolveTCPAddr(network, address string) (*TCPAddr, error)
-
func ResolveUDPAddr(network, address string) (*UDPAddr, error)
下面是对这两个函数的源码分析。
ResolveTCPAddr
该函数返回的地址包含的信息如下:
// src/net/tcpsock.go type TCPAddr struct { IP IP Port int Zone string // IPv6 scoped addressing zone }
TCPAddr里, IP
既可以是 IPv4 地址,也可以是 IPv6 地址。 Port
就是端口了。 Zone
是 IPv6 本地地址所在的区域。
从返回结果看该函数的参数, network
指 address
的网络类型; address
指要解析的地址,会从中解析出我们想要的 IP
, Port
和 Zone
。
源码分析
// src/net/ipsock.go func ResolveTCPAddr(network, address string) (*TCPAddr, error) { // 检查 `network` 的值 switch network { case "tcp", "tcp4", "tcp6": case "": // a hint wildcard for Go 1.0 undocumented behavior network = "tcp" default: return nil, UnknownNetworkError(network) } // 使用默认解析器对 `address` 进行解析 addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address) if err != nil { return nil, err } // 根据 `network` 和 `address` 返回一个地址 return addrs.forResolve(network, address).(*TCPAddr), nil }
从源码中可以看出,参数 network
只能是如下四个值,否则会得到一个错误。
默认解析器解析地址后返回一个地址列表 addrs
,该地址列表既包含了 IPv4 地址,也包含了 IPv6 地址。
-
"": 将
network
置为 "tcp",这是因为在使用默认解析器对address
进行解析时根据network
返回 TCP 地址*TCPAddr
。 -
"tcp": 若
address
是 IPv6 地址,则该函数返回addrs
中的第一个IP
是 IPv6 的地址,否则返回addrs
中的第一个IP
是 IPv4 的地址。 -
"tcp4": 该函数返回
addrs
中的第一个IP
是 IPv4 的地址。 -
"tcp6": 该函数返回
addrs
中的第一个IP
是 IPv6 的地址。
addrs.forResolve
相关源码如下:
// src/net/ipsock.go // An addrList represents a list of network endpoint addresses. type addrList []Addr // isIPv4 reports whether addr contains an IPv4 address. func isIPv4(addr Addr) bool { switch addr := addr.(type) { case *TCPAddr: return addr.IP.To4() != nil ... } return false } // isNotIPv4 reports whether addr does not contain an IPv4 address. func isNotIPv4(addr Addr) bool { return !isIPv4(addr) } // forResolve returns the most appropriate address in address for // a call to ResolveTCPAddr, ResolveUDPAddr, or ResolveIPAddr. // IPv4 is preferred, unless addr contains an IPv6 literal. func (addrs addrList) forResolve(network, addr string) Addr { var want6 bool switch network { ... case "tcp", "udp": // IPv6 literal. (addr contains a port, so look for '[') want6 = count(addr, '[') > 0 } if want6 { return addrs.first(isNotIPv4) } return addrs.first(isIPv4) } // first returns the first address which satisfies strategy, or if // none do, then the first address of any kind. func (addrs addrList) first(strategy func(Addr) bool) Addr { for _, addr := range addrs { if strategy(addr) { return addr } } return addrs[0] }
ResolveUDPAddr
解析过程跟 ResolveTCPAddr
的一样,不过得到的是 *UDPAddr
。
UDPAddr
包含的信息如下:
// src/net/udpsock.go type UDPAddr struct { IP IP Port int Zone string // IPv6 scoped addressing zone }
源码分析
// src/net/udpsock.go func ResolveUDPAddr(network, address string) (*UDPAddr, error) { // 检查 `network` 的值 switch network { case "udp", "udp4", "udp6": case "": // a hint wildcard for Go 1.0 undocumented behavior network = "udp" default: return nil, UnknownNetworkError(network) } // 使用默认解析器对 `address` 进行解析 addrs, err := DefaultResolver.internetAddrList(context.Background(), network, address) if err != nil { return nil, err } // 根据 `network` 和 `address` 返回一个地址 return addrs.forResolve(network, address).(*UDPAddr), nil }
Reference
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK