Net
Overview
net包提供了可移植的网络I/O接口,包括TCP/IP,UDP,域名解析,Unix域socket,尽管包提供了接近底层网络原语的方法,但是大多数客户只需要由Dial, Listen, Accept函数和相关的Conn和Listener接口提供的基础的设施,crypto/tls包提供相同的函数和相似的Dial和Listen函数域名解析
解析域名的方法,不论是间接的使用函数比如Dial,或直接的使用函数LookupHost和LookupAddr,因系统而异 对于Unix系统,解析器有两种方法解析名字,直接发送DNS请求到在/etc/resolv.conf的服务器能够使用go的原生解析器,或使用调用c library routines比如getaddrinfo,getaddrinfo的cgo-based的解析器 默认使用原生的解析器,因为一个阻塞的DNS请求只需要消费一个goroutine,但是一个阻塞的C调用消费一个操作系统线程,当cgo可用时,cgo-based resolver使用在各种条件之下:操作系统不允许程序直接发送DNS请求(OS X),当LOCALDOMAIN环境存在的话(即使是空),当RES_OPTION或HOSTALIASES环境变量是非空的,当ASR_CONFIG环境变量是非空的(OpenBSD only),当/etc/resolv.conf或者/etc/nsswitch.conf指定使用的特征,GO resolver 没有实现,当名字查找以.local结尾或是一个组播DNS名字 解析器的决定能够被设置GODEBUG环境变量值netdns,可以查看go or cgo (package runtime),比如export GODEBUG=netdns=go // force pure go resolver
export GODEBUG=netdns=cgo // force cgo resolver
也可以在go编译时设定netgo或netcgo build tag
当netdns被设定为一个数字,比如GODEBUG=netdns=1,将会造成解析器打印关于决定的调试信息,为了强迫一个特定的解析器也打印调试信息,汇总两个设置通过添加一个符号,比如GODEBUG=netdns=go+1
对于Plan 9,解析器总是通过/net/cs和/net/dns
对于Windows,总是使用C Functions,如GetAddrInfo,DnsQuery
常量(Constants)
IP地址长度(bytes)const (
IPv4len = 4
IPv6len = 16
)
变量(Variables)
众所周知的IPv4地址
var (
IPv4bcast = IPv4(255, 255, 255, 255) // limited broadcast
IPv4allsys = IPv4(224, 0, 0, 1) // all systems
IPv4allrouter = IPv4(224, 0, 0, 2) // all routers
IPv4zero = IPv4(0, 0, 0, 0) // all zeros
)
众所周知的IPv6地址
var (
IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
IPv6interfacelocalallnodes = IP{0xff, 0x11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
)
默认的解析器是被包级的package-level的Lookup函数和没有指定解析器的Dialer使用
var DefaultResolver = &Resolver{}
被OpError包含的各种错误
var (
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)
函数(Functions)
func JoinHostPort(host, port string) string
JoinHostPort结合host和post到网络地址"host:port"格式,如果host包含冒号,如IPv6地址所示,它将会返回"[host]:port"func SplitHostPort(hostport string) (host string, port string, err error)
SplitHostPort分割网络地址格式"host:port", "host%zone:port", "[host]:port","[host%zone]:port"成host或host%zone和portfunc LookupAddr(addr string) (name []string, err error)
LookupAddr反向查找给出的地址,返回映射到地址的名字列表 当使用本地的C library解析器,最多一个结果将会被返回,为了绕过本地解析器,使用定制的解析器func LookupCNAME(host string) (cname string, err error)
LookupCNAME返回给出host的规范名字,调用者不必关心规范名称能够直接调用LookupHost,LookupIP直接,两者都将解析规范名称作为查找的一部分 规范名称是遵循零个或多个CNAME记录,LookupCNAME不会返回错误,如果host不包含DNS"CNMAE"记录,只要解析器解析地址记录func LookupHost(host string) (addr []string, err error)
LookupHost查找给出的主机名使用本地的解析器,返回主机地址的切片func LookupPort(network, service string) (port int, err error)
LookupPort查找关于network和service的portfunc LookupTXT(name string) ([]string, error)
返回给出域名的DNS TXT记录package main
import (
"fmt"
"net"
)
func main() {
addr := net.JoinHostPort("localhost", "8080")
fmt.Println(addr)
baiduAddrs, err := net.LookupHost("www.baidu.com")
if err != nil {
panic(err)
}
for _, addr := range baiduAddrs {
fmt.Println(addr)
}
baiduNames, err := net.LookupAddr("8.8.8.8")
if err != nil {
panic(err)
}
for _, name := range baiduNames {
fmt.Println(name)
}
cname, err := net.LookupCNAME("www.baidu.com")
if err != nil {
panic(err)
}
fmt.Println(cname)
port, err := net.LookupPort("tcp", "smtp")
if err != nil {
panic(err)
}
fmt.Println(port)
txts, err := net.LookupTXT("segmentfault.com")
if err != nil {
panic(err)
}
for _, txt := range txts {
fmt.Println(txt)
}
}
Conn
Conn是一个面向流的网络连接,多个goroutine可以在Conn上同时调用方法type Conn interface {
// Read从连接上读取数据
// Read可以设置超时并且返回一个错误Timeout() == true在固定的时间限制后
Read(b []byte) (n int, err error)
// Write写入数据到连接
// Write可以设置超时并返回一个错误Timeout() == true在固定的时间限制后
Write(b []byte) (n int, err error)
// Close关闭连接
// 所有的Read或Write阻塞操作将会非阻塞和返回错误
Close() error
// LocalAddr返回本地网络地址
LocalAddr() Addr
// RemoteAddr返回远程网络地址
RemoteAddr() Addr
// SetDeadline设置读和写的关联连接的截止时间
// 它等同于同时调用SetReadDeadline和SetWriteDeadline
// SetDeadline时间是I/O操作后的绝对时间,以timeout错误失败而不是阻塞
// deadline应用于所有未来和未决定的I/O操作
// 不仅是接下来的Read或Write操作
// 当超过了deadline,连接能够被刷新通过以后设置deadline
// 一个空闲的timeout能够被重复的扩展实现截止时间
// 在成功的调用Write和Read后
// 零值的t意味着I/O不会超时
// 注意:如果TCP连接keep-alive选项开启
// 默认是这样除非重写通过Dialer.KeepAlive或ListenConfig.KeepAlive
// keep-alive失败可能会造成timeout error,对于Unix系统keep-alive在I/O失败能
// 够被检测到,通过 errors.Is(syscall.ETIMEOUT)
SetDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
}
func Dial(network, address string) (Conn, error)
Dial连接地址通过指定的网络 众所周知的网络有:"tcp","tcp4"(IPv4 only), "tcp6"(IPv6 only), "udp", "udp4"(IPv4 only), "udp6"(IPv6 only), "ip", "ip4"(IPv4 only), "ip6"(IPv6 only), "unix", "unixgram", "unixpacket"对于TCP和UDP,地址有"host:port"的格式,host必须是IP地址字面量或是能够被解析成IP地址的主机名,port必须是端口的数值或服务名,如果地址是IPv6地址的字面量,则必须使用"[host]"将其包围,比如"[2001:db8::1]:80",当使用TCP,解析host有多个IP 地址,Dial将会尝试所有地址,直到成功 Examples:
Dial("tcp", "golang.org:http")
Dial("tcp", "192.0.2.1:http")
Dial("tcp", "198.51.100.1:80")
Dial("udp", "[2001:db8::1]:domain")
Dial("udp", "[fe80::1%lo0]:53")
Dial("tcp", ":80")
对于IP网络,网络必须是"ip","ip4", "ip6"紧接着冒号和一个原生的协议号或协议名,host必须是一个IPv4或带zone的IPv6地址字面量,操作系统对于不是众所周知的协议号的行为比如"0"和"255"取决于操作系统
Examples:
Dial("ip4:1", "192.0.2.1")
Dial("ip6:ipv6-icmp", "2001:db8::1")
Dial("ip6:58", "fe80::1%lo0")
对于TCP,UDP,IP网络,不正确的地址将会被假定为本地地址
对于Unix网络,地址必须是文件系统的路径
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
DialTiemout和Dial行为类似但是需要超时 超时包括名字解析,如果需要的话,当使用TCP,主机地址被解析成多个网络地址,timeout将会被分割到每个连续的dial,因此每个都有适当的连接时间func FileConn(f *os.File) (c Conn, err error)
FileConn返回一个连接的复制通过打开一个文件,调用负责关闭文件当完成时,关闭c不起作用,关闭文件不会影响cListener
Listener是通用的面向流协议的网络监听者 多个goroutine可以同时在Listener上调用方法type Listener interface {
// Accept等待和返回下一个连接到Listener
Accept() (Conn, error)
// Close关闭监听者
// 任何阻塞的Accept操作变为非阻塞且返回错误
Close() error
// Addr返回监听者的网络地址
Addr() error
}
func FileListener(f os.File) (ln Listener, err error)
FileListener返回网络监听者的副本通过打开文件f,调用者负责关闭文件,关闭文件不影响ln,关闭ln不影响文件func Listen(network, address string) (Listenr, error)
在本地网络地址监听 network必须是"tcp", "tcp4", "tcp6", "unix" or "unixpacket"Example
server.go
package main
import (
"net"
"fmt"
)
func main() {
listener, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", "16000"))
if err != nil {
panic(err)
}
for {
conn, err := listener.Accept()
if err != nil {
break
}
go func() {
buf := make([]byte, 1024)
n, _ := conn.Read(buf)
fmt.Println(string(buf[:n]))
conn.Write([]byte("hello, i am your server"))
defer conn.Close()
}()
}
}
client.go
package main
import (
"net"
"fmt"
"strings"
"bytes"
)
func main() {
conn, err := net.Dial("tcp", net.JoinHostPort("127.0.0.1", "16000"))
if err != nil {
panic(err)
}
r := strings.NewReader("hello, i'm your client")
_, err = r.WriteTo(conn)
if err != nil {
panic(err)
}
buf := new(bytes.Buffer)
_, err = buf.ReadFrom(conn)
if err != nil {
panic(err)
}
fmt.Println(buf.String())
fmt.Println("bye, bye!")
defer conn.Close()
}
Pipe
func Pipe() (Conn, Conn)
Pipe创建一个同步,基于内存的全双工网络连接,两端都实现了Conn接口,Read操作匹配另一端的写操作,直接在二者拷贝数据而不经过缓冲区Buffers
Buffers包含零个或多个要写入的bytes 对于明确的机器,对于明确的连接类型,这是理想化的操作系统特定写操作批处理(比如"writev")type Buffers [][]byte
func (*Buffers) Read(p []byte) (n int, err error)
func (*Buffers) WriteTo(w io.Writer) (n int64, err error)