参考:https://studygolang.com/pkgdoc

导入方式:

import "net"

net包提供了可移植的网络I/O接口,包括TCP/IP、UDP、域名解析和Unix域socket。

虽然本包提供了对网络原语的访问,大部分使用者只需要Dial、Listen和Accept函数提供的基本接口;以及相关的Conn和Listener接口。crypto/tls包提供了相同的接口和类似的Dial和Listen函数。

1)IP

type IP

type IP []byte

IP类型是代表单个IP地址的[]byte切片。本包的函数都可以接受4字节(IPv4)和16字节(IPv6)的切片作为输入。

注意,IP地址是IPv4地址还是IPv6地址是语义上的属性,而不取决于切片的长度:16字节的切片也可以是IPv4地址。

func IPv4

func IPv4(a, b, c, d byte) IP

IPv4返回包含一个IPv4地址a.b.c.d的IP地址(16字节格式)。

func ParseIP

func ParseIP(s string) IP

ParseIP将s解析为IP地址,并返回该地址。如果s不是合法的IP地址文本表示,ParseIP会返回nil。

字符串可以是小数点分隔的IPv4格式(如"74.125.19.99")或IPv6格式(如"2001:4860:0:2001::68")格式。

举例:

package main
import(
"fmt"
"net"
"reflect"
) var parseIPTests = []struct {
in string
out net.IP
}{
{"127.0.1.2", net.IPv4(, , , )},
{"127.0.0.1", net.IPv4(, , , )},
{"127.001.002.003", net.IPv4(, , , )},
{"::ffff:127.1.2.3", net.IPv4(, , , )},
{"::ffff:127.001.002.003", net.IPv4(, , , )},
{"::ffff:7f01:0203", net.IPv4(, , , )},
{"0:0:0:0:0000:ffff:127.1.2.3", net.IPv4(, , , )},
{"0:0:0:0:000000:ffff:127.1.2.3", net.IPv4(, , , )},
{"0:0:0:0::ffff:127.1.2.3", net.IPv4(, , , )}, {"2001:4860:0:2001::68", net.IP{0x20, 0x01, 0x48, 0x60, , , 0x20, 0x01, , , , , , , 0x00, 0x68}},
{"2001:4860:0000:2001:0000:0000:0000:0068", net.IP{0x20, 0x01, 0x48, 0x60, , , 0x20, 0x01, , , , , , , 0x00, 0x68}}, {"-0.0.0.0", nil},
{"0.-1.0.0", nil},
{"0.0.-2.0", nil},
{"0.0.0.-3", nil},
{"127.0.0.256", nil},
{"abc", nil},
{"123:", nil},
{"fe80::1%lo0", nil},
{"fe80::1%911", nil},
{"", nil},
{"a1:a2:a3:a4::b1:b2:b3:b4", nil}, // Issue 6628
} func main() {
for i, tt := range parseIPTests {
if out := net.ParseIP(tt.in); !reflect.DeepEqual(out, tt.out) {//如果得到的out与上面的结构体中out的值不等的话,就返回错误
fmt.Errorf("ParseIP(%q) = %v, want %v", tt.in, out, tt.out)
} else{
fmt.Printf("%v out is : %v\n", i, out)
}
if tt.in == "" { //如果in为空,则跳出该循环,继续下一个循环
fmt.Println("%v is '' ")
continue
}
var out net.IP
//解码tt.in为IP,并将值输入out,如果该out与tt.out不等,或者运行UnmarshalText出错(即无out值)但tt.out不为nil,或者运行UnmarshalText没出错(即有out值)但tt.out为nil的情况下则报错
if err := out.UnmarshalText([]byte(tt.in)); !reflect.DeepEqual(out, tt.out) || (tt.out == nil) != (err != nil) {
fmt.Errorf("IP.UnmarshalText(%q) = %v, %v, want %v", tt.in, out, err, tt.out)
}else{
fmt.Printf("%v out is : %v\n", i, out)
}
}
}

返回:

userdeMBP:go-learning user$ go run test.go 127.0.0.1
out is : 127.0.1.2
out is : 127.0.1.2
out is : 127.0.0.1
out is : 127.0.0.1
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : 127.1.2.3
out is : :::::
out is : :::::
out is : :::::
out is : :::::
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
out is : <nil>
%v is ''
out is : <nil>
out is : <nil>

func (IP) String

func (ip IP) String() string

String返回IP地址ip的字符串表示。如果ip是IPv4地址,返回值的格式为点分隔的,如"74.125.19.99";否则表示为IPv6格式,如"2001:4860:0:2001::68"。

举例:

package main
import(
"fmt"
"os"
"net"
) func main() {
if len(os.Args) != 2{
fmt.Fprintf(os.Stderr, "Usage: %s ip-addr\n", os.Args[0])
os.Exit(1)
}
name := os.Args[1]
addr := net.ParseIP(name)
if addr == nil {
fmt.Println("Invalid address")
}else{
fmt.Println("the address is", addr.String())
}
os.Exit(0)
}

返回:

userdeMacBook-Pro:go-learning user$ go run test.go
Usage: /var/folders/2_/g5wrlg3x75zbzyqvsd5f093r0000gn/T/go-build258331112/b001/exe/test ip-addr
exit status 1
userdeMacBook-Pro:go-learning user$ go run test.go 127.0.0.1
the address is 127.0.0.1

func (IP) MarshalText

func (ip IP) MarshalText() ([]byte, error)

MarshalText实现了encoding.TextMarshaler接口,返回值和String方法一样。即将ip的值编码为[]byte类型返回

func (*IP) UnmarshalText

func (ip *IP) UnmarshalText(text []byte) error

UnmarshalText实现了encoding.TextUnmarshaler接口。IP地址字符串应该是ParseIP函数可以接受的格式。即将text的值解码为IP类型然后存储到ip中

举例:

package main
import(
"fmt"
"net"
"log"
"reflect"
)
func main() {
for _, in := range [][]byte{[]byte("127.0.1.2"), []byte("0:0:0:0:0000:ffff:127.1.2.3")} {
var out = net.IP{, , , }
//err应该为nil,且out应该为nil,这样才不会报错,解码in的值将写到out中
if err := out.UnmarshalText(in); err != nil || out == net.IP{, , , } {
fmt.Errorf("UnmarshalText(%v) = %v, %v; want nil, nil", in, out, err)
}else{
fmt.Printf("in is : %q, out is %v\n", in, out)
}
}
var ip = net.IP{, , , }
//将ip编码为[]byte类型,返回got
got, err := ip.MarshalText()
if err != nil {
log.Fatal(err)
}
//got应该等于[]byte("")
if !reflect.DeepEqual(got, []byte("1.2.3.4")) {
fmt.Errorf(`got %#v, want []byte("")`, got)
}else{
fmt.Printf("got is : %q\n", got)
}
}

返回:

userdeMBP:go-learning user$ go run test.go 127.0.0.1
in is : "127.0.1.2", out is 127.0.1.2
in is : "0:0:0:0:0000:ffff:127.1.2.3", out is 127.1.2.3
got is : "1.2.3.4"

func (IP) IsGlobalUnicast

func (ip IP) IsGlobalUnicast() bool

如果ip是全局单播地址,则返回真。

func (IP) IsLinkLocalUnicast

func (ip IP) IsLinkLocalUnicast() bool

如果ip是链路本地单播地址,则返回真。

func (IP) IsInterfaceLocalMulticast

func (ip IP) IsInterfaceLocalMulticast() bool

如果ip是接口本地组播地址,则返回真。

func (IP) IsLinkLocalMulticast

func (ip IP) IsLinkLocalMulticast() bool

如果ip是链路本地组播地址,则返回真。

func (IP) IsMulticast

func (ip IP) IsMulticast() bool

如果ip是组播地址,则返回真。

func (IP) IsLoopback

func (ip IP) IsLoopback() bool

如果ip是环回地址,则返回真。

func (IP) IsUnspecified

func (ip IP) IsUnspecified() bool

如果ip是未指定地址,则返回真。

func (IP) Equal

func (ip IP) Equal(x IP) bool

如果ip和x代表同一个IP地址,Equal会返回真。代表同一地址的IPv4地址和IPv6地址也被认为是相等的。

func (IP) To16

func (ip IP) To16() IP

To16将一个IP地址转换为16字节表示。如果ip不是一个IP地址(长度错误),To16会返回nil。

func (IP) To4

func (ip IP) To4() IP

To4将一个IPv4地址转换为4字节表示。如果ip不是IPv4地址,To4会返回nil。

func (IP) DefaultMask

func (ip IP) DefaultMask() IPMask

函数返回IP地址ip的默认子网掩码。只有IPv4有默认子网掩码;如果ip不是合法的IPv4地址,会返回nil。

func (IP) Mask

func (ip IP) Mask(mask IPMask) IP

Mask方法认为mask为ip的子网掩码,返回ip的网络地址部分的ip。(主机地址部分都置0)

举例:

package main
import(
"fmt"
"net"
// "log"
// "reflect"
) func main() {
var ip = net.IP{, , , }
fmt.Println(ip.DefaultMask()) //ff000000,即255.0.0.0
fmt.Printf("%q\n", ip) //"127.168.124.1"
//将子网掩码设为255.255.0.0后,返回的ip将会符合对应的子网掩码,所以返回"127.168.0.0"
//如果设置的是255.0.0.0,则返回"127.0.0.0"
ip = ip.Mask(net.IPv4Mask(, , , ))
fmt.Printf("%q\n", ip) //"127.168.0.0"
}

type ParseError

type ParseError struct {
Type string
Text string
}

ParseError代表一个格式错误的字符串,Type为期望的格式。

func (*ParseError) Error

func (e *ParseError) Error() string

func ParseCIDR

func ParseCIDR(s string) (IP, *IPNet, error)

ParseCIDR将s作为一个CIDR(无类型域间路由)的IP地址和掩码字符串,如"192.168.100.1/24"或"2001:DB8::/48",解析并返回IP地址和IP网络,参见RFC 4632RFC 4291

本函数会返回IP地址和该IP所在的网络和掩码。例如,ParseCIDR("192.168.100.1/16")会返回IP地址192.168.100.1和IP网络192.168.0.0/16。

举例:

package main
import(
"fmt"
"net"
// "log"
"reflect"
) var parseCIDRTests = []struct {
in string
ip net.IP
net *net.IPNet
err error
}{
{"135.104.0.0/32", net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.IPv4Mask(, , , )}, nil},
{"0.0.0.0/24", net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.IPv4Mask(, , , )}, nil},
{"135.104.0.1/24", net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.IPv4Mask(, , , )}, nil},
{"::1/128", net.ParseIP("::1"), &net.IPNet{IP: net.ParseIP("::1"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"))}, nil},
{"abcd:2345::/127", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe"))}, nil},
{"abcd:2345::/65", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff:8000::"))}, nil},
{"abcd:2345::/64", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))}, nil},
{"abcd:2345::/63", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:fffe::"))}, nil},
{"abcd:2345::/33", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:8000::"))}, nil},
{"abcd:2345::/32", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2345::"), Mask: net.IPMask(net.ParseIP("ffff:ffff::"))}, nil},
{"abcd:2344::/31", net.ParseIP("abcd:2344::"), &net.IPNet{IP: net.ParseIP("abcd:2344::"), Mask: net.IPMask(net.ParseIP("ffff:fffe::"))}, nil},
{"abcd:2300::/24", net.ParseIP("abcd:2300::"), &net.IPNet{IP: net.ParseIP("abcd:2300::"), Mask: net.IPMask(net.ParseIP("ffff:ff00::"))}, nil},
{"abcd:2345::/24", net.ParseIP("abcd:2345::"), &net.IPNet{IP: net.ParseIP("abcd:2300::"), Mask: net.IPMask(net.ParseIP("ffff:ff00::"))}, nil},
{"2001:DB8::/48", net.ParseIP("2001:DB8::"), &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, nil},
{"2001:DB8::1/48", net.ParseIP("2001:DB8::1"), &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))}, nil},
{"192.168.1.1/255.255.255.0", nil, nil, &net.ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
{"192.168.1.1/35", nil, nil, &net.ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
{"2001:db8::1/-1", nil, nil, &net.ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
{"-0.0.0.0/32", nil, nil, &net.ParseError{Type: "CIDR address", Text: "-0.0.0.0/32"}},
{"0.0.0.-3/32", nil, nil, &net.ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
{"0.0.0.0/-0", nil, nil, &net.ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
{"", nil, nil, &net.ParseError{Type: "CIDR address", Text: ""}},
} func main() {
for i, tt := range parseCIDRTests {
ip, net, err := net.ParseCIDR(tt.in)
//如果返回的err不是nil或者自定义的net.ParseError,那么将报错
if !reflect.DeepEqual(err, tt.err) {
fmt.Errorf("ParseCIDR(%q) = %v, %v; want %v, %v", tt.in, ip, net, tt.ip, tt.net)
}
//ParseCIDR没出错,且返回的ip,net和给出的值都相等则成功,否则报错
if err == nil{
if !tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !reflect.DeepEqual(net.Mask, tt.net.Mask) {
fmt.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v, {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
}else{
fmt.Printf("%v ParseCIDR(%q) = %v, {%v, %q}\n", i, tt.in, ip, net.IP, net.Mask)
}
} }
}

返回:

userdeMBP:go-learning user$ go run test.go
ParseCIDR("135.104.0.0/32") = 135.104.0.0, {135.104.0.0, "ffffffff"}
ParseCIDR("0.0.0.0/24") = 0.0.0.0, {0.0.0.0, "ffffff00"}
ParseCIDR("135.104.0.1/24") = 135.104.0.1, {135.104.0.0, "ffffff00"}
ParseCIDR("::1/128") = ::, {::, "ffffffffffffffffffffffffffffffff"}
ParseCIDR("abcd:2345::/127") = abcd:::, {abcd:::, "fffffffffffffffffffffffffffffffe"}
ParseCIDR("abcd:2345::/65") = abcd:::, {abcd:::, "ffffffffffffffff8000000000000000"}
ParseCIDR("abcd:2345::/64") = abcd:::, {abcd:::, "ffffffffffffffff0000000000000000"}
ParseCIDR("abcd:2345::/63") = abcd:::, {abcd:::, "fffffffffffffffe0000000000000000"}
ParseCIDR("abcd:2345::/33") = abcd:::, {abcd:::, "ffffffff800000000000000000000000"}
ParseCIDR("abcd:2345::/32") = abcd:::, {abcd:::, "ffffffff000000000000000000000000"}
ParseCIDR("abcd:2344::/31") = abcd:::, {abcd:::, "fffffffe000000000000000000000000"}
ParseCIDR("abcd:2300::/24") = abcd:::, {abcd:::, "ffffff00000000000000000000000000"}
ParseCIDR("abcd:2345::/24") = abcd:::, {abcd:::, "ffffff00000000000000000000000000"}
ParseCIDR("2001:DB8::/48") = :db8::, {:db8::, "ffffffffffff00000000000000000000"}
ParseCIDR("2001:DB8::1/48") = :db8::, {:db8::, "ffffffffffff00000000000000000000"}

type IPMask

type IPMask []byte

IPMask代表一个IP地址的掩码。

func IPv4Mask

func IPv4Mask(a, b, c, d byte) IPMask

IPv4Mask返回一个4字节格式的IPv4掩码a.b.c.d。

func CIDRMask

func CIDRMask(ones, bits int) IPMask

CIDRMask返回一个IPMask类型值,该返回值总共有bits个字位,其中前ones个字位都是1,其余字位都是0。

func (IPMask) Size

func (m IPMask) Size() (ones, bits int)

Size返回m的前导的1字位数和总字位数。如果m不是规范的子网掩码(字位:/^1+0+$/),将返会(0, 0)。

func (IPMask) String

func (m IPMask) String() string

String返回m的十六进制格式,没有标点。

type IPNet

type IPNet struct {
IP IP // 网络地址
Mask IPMask // 子网掩码
}

IPNet表示一个IP网络。

func (*IPNet) Contains

func (n *IPNet) Contains(ip IP) bool

Contains报告该网络是否包含地址ip。

func (*IPNet) Network

func (n *IPNet) Network() string

Network返回网络类型名:"ip+net",注意该类型名是不合法的。

func (*IPNet) String

func (n *IPNet) String() string

String返回n的CIDR表示,如"192.168.100.1/24"或"2001:DB8::/48",参见RFC 4632RFC 4291

如果n的Mask字段不是规范格式,它会返回一个包含n.IP.String()、斜线、n.Mask.String()(此时表示为无标点十六进制格式)的字符串,如"192.168.100.1/c000ff00"。

举例:

package main
import(
"fmt"
"net"
// "log"
// "reflect"
) var ipNetContainsTests = []struct {
ip net.IP
net *net.IPNet
ok bool
}{
{net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.CIDRMask(, )}, true},
{net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.CIDRMask(, )}, false},
{net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.IPv4Mask(, , , )}, true},
{net.IPv4(, , , ), &net.IPNet{IP: net.IPv4(, , , ), Mask: net.IPv4Mask(, , , )}, false},
{net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.CIDRMask(, )}, true},
{net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:2::"), Mask: net.CIDRMask(, )}, false},
{net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.IPMask(net.ParseIP("ffff:0:ffff::"))}, true},
{net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.IPMask(net.ParseIP("0:0:0:ffff::"))}, false},
} func main() {
for _, tt := range ipNetContainsTests {
if ok := tt.net.Contains(tt.ip); ok != tt.ok {
fmt.Errorf("IPNet(%v).Contains(%v) = %v, want %v", tt.net, tt.ip, ok, tt.ok)
}else{
fmt.Printf("string is : %s\n", tt.net.String())
fmt.Printf("network is : %s\n",tt.net.Network())
}
}
}

返回:

userdeMBP:go-learning user$ go run test.go
string is : 172.16.0.0/
network is : ip+net
string is : 172.16.0.0/
network is : ip+net
string is : 192.168.0.0/0000fffc
network is : ip+net
string is : 192.168.0.0/00ff00fc
network is : ip+net
string is : :db8:::/
network is : ip+net
string is : :db8:::/
network is : ip+net
string is : :db8:::/ffff0000ffff00000000000000000000
network is : ip+net
string is : :db8:::/000000000000ffff0000000000000000
network is : ip+net

2)实现TCP Socket——TCPConn、TCPAddr、TCPListener

客户端使用的三个方法

type TCPConn

type TCPConn struct {
// 内含隐藏或非导出字段
}

TCPConn代表一个TCP网络连接,实现了Conn接口。

func DialTCP

func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)

DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。

参数net必须是"tcp"、"tcp4"、"tcp6",表示(IPv4\IPv6任意一个)、(IPv4-only)或者(IPv6-only);

laddr表示本机地址,一般为nil.如果laddr不是nil,将使用它作为本地地址,即客户端,否则自动选择一个本地地址;

raddr表示远程的服务地址,即服务端

func (*TCPConn) Read

func (c *TCPConn) Read(b []byte) (int, error)

Read实现了Conn接口Read方法,客户端读取服务端响应回来的内容

func (*TCPConn) Write

func (c *TCPConn) Write(b []byte) (int, error)

Write实现了Conn接口Write方法,客户端将请求写入conn中发送给服务端

控制TCP连接函数有:

func (*TCPConn) SetKeepAlive

func (c *TCPConn) SetKeepAlive(keepalive bool) error

SetKeepAlive设置操作系统是否应该在该连接中发送keepalive信息

type TCPAddr

type TCPAddr struct {
IP IP
Port int
Zone string // IPv6范围寻址域
}

TCPAddr代表一个TCP终端地址。

func ResolveTCPAddr

func ResolveTCPAddr(net, addr string) (*TCPAddr, error)

ResolveTCPAddr将addr作为TCP地址解析并返回。

参数addr表示域名或IP地址,如“www.baidu.com:80”或“127.0.0.1:22”。格式为"host:port"或"[ipv6-host%zone]:port",解析得到网络名和端口名;

net参数必须是"tcp"、"tcp4"或"tcp6",表示(IPv4\IPv6任意一个)、(IPv4-only)或者(IPv6-only)。

IPv6地址字面值/名称必须用方括号包起来,如"[::1]:80"、"[ipv6-host]:http"或"[ipv6-host%zone]:80"。

服务端实现监听使用的函数:

type TCPListener

type TCPListener struct {
// 内含隐藏或非导出字段
}

TCPListener代表一个TCP网络的监听者。使用者应尽量使用Listener接口而不是假设(网络连接为)TCP。

func ListenTCP

func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error)

ListenTCP在本地TCP地址laddr上声明并返回一个*TCPListener,net参数必须是"tcp"、"tcp4"、"tcp6",如果laddr的端口字段为0,函数将选择一个当前可用的端口,可以用Listener的Addr方法获得该端口。

func (*TCPListener) Accept

func (l *TCPListener) Accept() (Conn, error)

Accept用于实现Listener接口的Accept方法;他会等待下一个呼叫,并返回一个该呼叫的Conn接口。

适用上面的函数实现的客户端和服务端实现简单的时间同步服务,监听1200端口

客户端为:

package main
import(
"fmt"
"net"
"os"
) func checkError(index int, err error){
if err != nil{
fmt.Fprintf(os.Stderr, "index : %v,Fatal error : %s", index, err.Error())
os.Exit()
}
} func main() {
if len(os.Args) != {
fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[])
os.Exit()
}
service := os.Args[]
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(, err) //创建一个TCP连接conn
conn, err := net.DialTCP("tcp", nil, tcpAddr)
checkError(, err) //通过conn来发送请求信息
_, err = conn.Write([]byte("HEAD / HTTP/1.0 \r\n\r\n"))
checkError(, err) //从conn中读取服务端返回的全部的文本
rsp := make([]byte, )
n, err := conn.Read(rsp)
checkError(, err)
fmt.Printf("receive %d bytes in response : %q\n", n, rsp[:n]) os.Exit()
}

服务端为:

package main
import(
"fmt"
"net"
"os"
"time"
) func checkError(err error){
if err != nil{
fmt.Fprintf(os.Stderr, "Fatal error : %s", err.Error())
os.Exit()
}
} func main() {
service := ":1200"
tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
checkError(err) listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err) for{
conn, err := listener.Accept()
if err != nil{
continue
}
go handleerClient(conn)
}
} func handleerClient(conn net.Conn){
defer conn.Close()
daytime := time.Now().String()
conn.Write([]byte(daytime))
}

客户端返回:

userdeMBP:go-learning user$ go run test.go 127.0.0.1:
receive bytes in response : "2019-02-27 15:25:02.113373 +0800 CST m=+5.168778770"

3)实现UDP Socket — UDPConn、UDPAddr

type UDPConn

type UDPConn struct {
// 内含隐藏或非导出字段
}

UDPConn代表一个UDP网络连接,实现了Conn和PacketConn接口。

func DialUDP

func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error)

DialTCP在网络协议net上连接本地地址laddr和远端地址raddr。net必须是"udp"、"udp4"、"udp6";如果laddr不是nil,将使用它作为本地地址,否则自动选择一个本地地址。

func ListenUDP

func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error)

ListenUDP创建一个接收目的地是本地地址laddr的UDP数据包的网络连接。net必须是"udp"、"udp4"、"udp6";如果laddr端口为0,函数将选择一个当前可用的端口,可以用Listener的Addr方法获得该端口。返回的*UDPConn的ReadFrom和WriteTo方法可以用来发送和接收UDP数据包(每个包都可获得来源地址或设置目标地址)。

func (*UDPConn) Read

func (c *UDPConn) Read(b []byte) (int, error)

Read实现Conn接口Read方法

func (*UDPConn) ReadFrom

func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error)

ReadFrom实现PacketConn接口ReadFrom方法

func (*UDPConn) ReadFromUDP

func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error)

ReadFromUDP从c读取一个UDP数据包,将有效负载拷贝到b,返回拷贝字节数和数据包来源地址。

ReadFromUDP方法会在超过一个固定的时间点之后超时,并返回一个错误。

func (*UDPConn) Write

func (c *UDPConn) Write(b []byte) (int, error)

Write实现Conn接口Write方法

func (*UDPConn) WriteTo

func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error)

WriteTo实现PacketConn接口WriteTo方法

func (*UDPConn) WriteToUDP

func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error)

WriteToUDP通过c向地址addr发送一个数据包,b为包的有效负载,返回写入的字节。

WriteToUDP方法会在超过一个固定的时间点之后超时,并返回一个错误。在面向数据包的连接上,写入超时是十分罕见的。

type UDPAddr

type UDPAddr struct {
IP IP
Port int
Zone string // IPv6范围寻址域
}

UDPAddr代表一个UDP终端地址。

func ResolveUDPAddr

func ResolveUDPAddr(net, addr string) (*UDPAddr, error)

ResolveTCPAddr将addr作为TCP地址解析并返回。参数addr格式为"host:port"或"[ipv6-host%zone]:port",解析得到网络名和端口名;net必须是"udp"、"udp4"或"udp6"。

IPv6地址字面值/名称必须用方括号包起来,如"[::1]:80"、"[ipv6-host]:http"或"[ipv6-host%zone]:80"。

客户端:

package main
import(
"fmt"
"net"
"os"
) func checkError(index int, err error){
if err != nil{
fmt.Fprintf(os.Stderr, "index : %v,Fatal error : %s", index, err.Error())
os.Exit()
}
} func main() {
if len(os.Args) != {
fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[])
os.Exit()
}
service := os.Args[]
udpAddr, err := net.ResolveUDPAddr("udp", service)
checkError(, err) //创建一个TCP连接conn
conn, err := net.DialUDP("udp", nil, udpAddr)
defer conn.Close()
checkError(, err) //通过conn来发送请求信息
_, err = conn.Write([]byte("anything"))
checkError(, err) //从conn中读取服务端返回的全部的文本
var rsp []byte
n, err := conn.Read(rsp[:])
checkError(, err) fmt.Printf("receive %d bytes in response : %q\n", n, rsp[:n])
os.Exit()
}

服务端

package main
import(
"fmt"
"net"
"os"
"time"
) func checkError(err error){
if err != nil{
fmt.Fprintf(os.Stderr, "Fatal error : %s", err.Error())
os.Exit()
}
} func main() {
service := ":11200"
udpAddr, err := net.ResolveUDPAddr("udp", service)
checkError(err) conn, err := net.ListenUDP("udp", udpAddr)
defer conn.Close()
checkError(err) for{
go handlerClient(conn)
}
} func handlerClient(conn *net.UDPConn){
var rsp []byte
_, addr, err := conn.ReadFromUDP(rsp[:])
if err != nil{
return
}
daytime := time.Now().String()
conn.WriteToUDP([]byte(daytime), addr)
}

客户端返回:

userdeMBP:go-learning user$ go run test.go 127.0.0.1:
receive bytes in response : "2019-02-27 16:25:46.905443 +0800 CST m=+2.197257345"

)查询操作

func LookupHost

func LookupHost(host string) (addrs []string, err error)

LookupHost函数查询主机的网络地址序列。

func LookupIP

func LookupIP(host string) (addrs []IP, err error)

LookupIP函数查询主机的ipv4和ipv6地址序列。

举例:

package main
import(
"fmt"
"net"
"reflect"
) var parseIPTests = []struct {
in string
out net.IP
}{
{"127.0.1.2", net.IPv4(, , , )},
{"127.0.0.1", net.IPv4(, , , )},
{"127.001.002.003", net.IPv4(, , , )},
{"::ffff:127.1.2.3", net.IPv4(, , , )},
{"::ffff:127.001.002.003", net.IPv4(, , , )},
{"::ffff:7f01:0203", net.IPv4(, , , )},
{"0:0:0:0:0000:ffff:127.1.2.3", net.IPv4(, , , )},
{"0:0:0:0:000000:ffff:127.1.2.3", net.IPv4(, , , )},
{"0:0:0:0::ffff:127.1.2.3", net.IPv4(, , , )}, {"2001:4860:0:2001::68", net.IP{0x20, 0x01, 0x48, 0x60, , , 0x20, 0x01, , , , , , , 0x00, 0x68}},
{"2001:4860:0000:2001:0000:0000:0000:0068", net.IP{0x20, 0x01, 0x48, 0x60, , , 0x20, 0x01, , , , , , , 0x00, 0x68}},
} func main() {
_, err := net.LookupIP("")
if err == nil {
fmt.Errorf(`LookupIP("") succeeded, should fail`)
}
_, err = net.LookupHost("")
if err == nil {
fmt.Errorf(`LookupIP("") succeeded, should fail`)
} // Test that LookupHost and LookupIP, which normally
// expect host names, work with IP addresses.
for i, tt := range parseIPTests {
if tt.out != nil {
addrs, err := net.LookupHost(tt.in)
//len(addrs)应该等于1,addrs[0]应该为tt.in,err应该为nil,否则报错
if len(addrs) != || addrs[] != tt.in || err != nil {
fmt.Errorf("LookupHost(%q) = %v, %v, want %v, nil", tt.in, addrs, err, []string{tt.in})
}else{
fmt.Printf("%v LookupHost() addrs is : %v\n", i, addrs )
}
} if tt.out != nil {
ips, err := net.LookupIP(tt.in)
//len(ips)应该为1,ips[0]应该为等于tt.out,err应该为nil
if len(ips) != || !reflect.DeepEqual(ips[], tt.out) || err != nil {
fmt.Errorf("LookupIP(%q) = %v, %v, want %v, nil", tt.in, ips, err, []net.IP{tt.out})
}else{
fmt.Printf("%v LookupIP() ips is : %v\n", i, ips )
}
}
}
}

返回:

userdeMBP:go-learning user$ go run test.go 127.0.0.1
LookupHost() addrs is : [127.0.1.2]
LookupIP() ips is : [127.0.1.2]
LookupHost() addrs is : [127.0.0.1]
LookupIP() ips is : [127.0.0.1]
LookupHost() addrs is : [127.001.002.003]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [::ffff:127.1.2.3]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [::ffff:127.001.002.003]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [::ffff:7f01:]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [:::::ffff:127.1.2.3]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [:::::ffff:127.1.2.3]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [:::::ffff:127.1.2.3]
LookupIP() ips is : [127.1.2.3]
LookupHost() addrs is : [:::::]
LookupIP() ips is : [:::::]
LookupHost() addrs is : [:::::::]
LookupIP() ips is : [:::::]

func LookupAddr

func LookupAddr(addr string) (name []string, err error)

LookupAddr查询某个地址,返回映射到该地址的主机名序列,本函数和LookupHost不互为反函数。

未完待续

go标准库的学习-net的更多相关文章

  1. go标准库的学习-net/http

    参考:https://studygolang.com/pkgdoc 概念解释: request:用户请求的信息,用来解析用户的请求信息,包括post.get.cookie.url等信息 respons ...

  2. go标准库的学习-database/sql

    参考:https://studygolang.com/pkgdoc 导入方式: import "database/sql" sql包提供了保证SQL或类SQL数据库的泛用接口. 使 ...

  3. go标准库的学习-crypto/md5

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/md5" md5包实现了MD5哈希算法,参见RFC 1321. Con ...

  4. go标准库的学习-crypto/sha1

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174. ...

  5. go标准库的学习-crypto/sha256

    参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/sha256" sha256包实现了SHA224和SHA256哈希算法 ...

  6. python 标准库基础学习之开发工具部分1学习

    #2个标准库模块放一起学习,这样减少占用地方和空间#标准库之compileall字节编译源文件import compileall,re,sys#作用是查找到python文件,并把它们编译成字节码表示, ...

  7. python calendar标准库基础学习

    # -*- coding: utf-8 -*-# 作者:新手__author__ = 'Administrator'#标准库:日期时间基础学习:calendar:处理日期#例1import calen ...

  8. 《C标准库》学习笔记整理

    简介 <C标准库>书中对 C 标准库中的 15 个头文件的内容进行了详细的介绍,包括各头文件设计的背景知识.头文件中的内容.头文件中定义的函数和变量的使用.实现.测试等. 我学习此书的目的 ...

  9. python linecache标准库基础学习

    #python标准库基础之:linecacge:高效读取文本文件#说明与作用"""可以从文件或者导入python模块获取文件,维护一个结果缓存,从而可以更高效地从相同文件 ...

  10. python StringIO标准库基础学习

    #标准库:StringIO提供类文件API文本缓冲区#作用:可以处理内存中的文本,有2种不同的实现:cStringIP版本用c编写提高速度,StringIO用python来提供可移植性,与其他字符串连 ...

随机推荐

  1. java Future用法和意义一句话击破

    在并发编程时,一般使用runnable,然后扔给线程池完事,这种情况下不需要线程的结果. 所以run的返回值是void类型. 如果是一个多线程协作程序,比如菲波拉切数列,1,1,2,3,5,8...使 ...

  2. ArrayList和LinkedList的区别以及优缺点

    作用 ArrayList和LinkedList都是实现了List接口的容器类,用于存储一系列的对象引用.他们都可以对元素的增删改查进行操作. 对于ArrayList,它在集合的末尾删除或添加元素所用的 ...

  3. 【Dubbo&&Zookeeper】4、 Java实现Dubbo服务提供者及消费者注册

    转自:http://blog.csdn.net/u010317829/article/details/52128852 创建Mavn工程.HelloDubbo. pom.xml添加dubbo及spri ...

  4. csharp: FTP Client Library using System.Net.FtpClient and FluentFTP,测试中存在的BUG修正

    https://netftp.codeplex.com/ /// <summary> /// Gets a file listing from the server. Each FtpLi ...

  5. HTML常用标签及属性

    标签格式 格式: 双边:<标签名 属性1="值1" 属性2='值2' 属性3=值3>内容</标签名> 单边:<标签名 属性1="值1&quo ...

  6. HTML5是什么,以及优点和缺点

    HTML5是超文本标记语言HTML的第五次重大修改 HTML 5 的第一份正式草案已于2008年1月22日公布 2013年5月6日, HTML 5.1正式草案公布 HTML5的优缺点是什么?作为HTM ...

  7. vue.js 键盘enter事件的使用

    在监听键盘事件时,我们经常需要检查常见的键值.Vue 允许为 v-on 在监听键盘事件时添加按键修饰符: <!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -- ...

  8. JavaScript异步和单线程

    一,同步和异步的区别: 同步会阻塞代码执行,而异步不会.(比如alert是同步,setTimeout是异步) 二,前端使用异步的场景: 1,定时任务:setTimeout,setInterval 2, ...

  9. 方差variance, 协方差covariance, 协方差矩阵covariance matrix

    https://www.jianshu.com/p/e1c8270477bc?utm_campaign=maleskine&utm_content=note&utm_medium=se ...

  10. BI怎么选?重点看这10个技术指标

    2016年,商业智能市场火热,不管是投资圈还是IT圈,都在广泛关注着大数据和商业智能.宣传广告媒体报道见多了,不知道大家对BI选型的技术标准有谱了没.笔者对Gartner的BI魔力象限考评的15个关键 ...