go標準庫的學習-net

參考:https://studygolang.com/pkgdochtml

導入方式:golang

import "net"

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

雖然本包提供了對網絡原語的訪問,大部分使用者只須要Dial、Listen和Accept函數提供的基本接口;以及相關的Conn和Listener接口。crypto/tls包提供了相同的接口和相似的Dial和Listen函數。socket

1)IPtcp

type IP

type IP []byte

IP類型是表明單個IP地址的[]byte切片。本包的函數均可以接受4字節(IPv4)和16字節(IPv6)的切片做爲輸入。函數

注意,IP地址是IPv4地址仍是IPv6地址是語義上的屬性,而不取決於切片的長度:16字節的切片也能夠是IPv4地址。oop

 

func IPv4

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

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

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")格式。spa

舉例:

package main 
import(
    "fmt"
    "net"
    "reflect"
)

var parseIPTests = []struct {
    in  string
    out net.IP
}{
    {"127.0.1.2", net.IPv4(127, 0, 1, 2)},
    {"127.0.0.1", net.IPv4(127, 0, 0, 1)},
    {"127.001.002.003", net.IPv4(127, 1, 2, 3)},
    {"::ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"::ffff:127.001.002.003", net.IPv4(127, 1, 2, 3)},
    {"::ffff:7f01:0203", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0:0000:ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0:000000:ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0::ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},

    {"2001:4860:0:2001::68", net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
    {"2001:4860:0000:2001:0000:0000:0000:0068", net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 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
0 out is : 127.0.1.2
0 out is : 127.0.1.2
1 out is : 127.0.0.1
1 out is : 127.0.0.1
2 out is : 127.1.2.3
2 out is : 127.1.2.3
3 out is : 127.1.2.3
3 out is : 127.1.2.3
4 out is : 127.1.2.3
4 out is : 127.1.2.3
5 out is : 127.1.2.3
5 out is : 127.1.2.3
6 out is : 127.1.2.3
6 out is : 127.1.2.3
7 out is : 127.1.2.3
7 out is : 127.1.2.3
8 out is : 127.1.2.3
8 out is : 127.1.2.3
9 out is : 2001:4860:0:2001::68
9 out is : 2001:4860:0:2001::68
10 out is : 2001:4860:0:2001::68
10 out is : 2001:4860:0:2001::68
11 out is : <nil>
11 out is : <nil>
12 out is : <nil>
12 out is : <nil>
13 out is : <nil>
13 out is : <nil>
14 out is : <nil>
14 out is : <nil>
15 out is : <nil>
15 out is : <nil>
16 out is : <nil>
16 out is : <nil>
17 out is : <nil>
17 out is : <nil>
18 out is : <nil>
18 out is : <nil>
19 out is : <nil>
19 out is : <nil>
20 out is : <nil>
%v is '' 
21 out is : <nil>
21 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{1, 2, 3, 4}
        //err應該爲nil,且out應該爲nil,這樣纔不會報錯,解碼in的值將寫到out中
        if err := out.UnmarshalText(in); err != nil || out == net.IP{1, 2, 3, 4} {
            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{1, 2, 3, 4}
    //將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{127, 168, 124, 1}
    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(255, 255, 0, 0)) 
    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(135, 104, 0, 0), &net.IPNet{IP: net.IPv4(135, 104, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 255)}, nil},
    {"0.0.0.0/24", net.IPv4(0, 0, 0, 0), &net.IPNet{IP: net.IPv4(0, 0, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, nil},
    {"135.104.0.1/24", net.IPv4(135, 104, 0, 1), &net.IPNet{IP: net.IPv4(135, 104, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)}, 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
0 ParseCIDR("135.104.0.0/32") = 135.104.0.0, {135.104.0.0, "ffffffff"}
1 ParseCIDR("0.0.0.0/24") = 0.0.0.0, {0.0.0.0, "ffffff00"}
2 ParseCIDR("135.104.0.1/24") = 135.104.0.1, {135.104.0.0, "ffffff00"}
3 ParseCIDR("::1/128") = ::1, {::1, "ffffffffffffffffffffffffffffffff"}
4 ParseCIDR("abcd:2345::/127") = abcd:2345::, {abcd:2345::, "fffffffffffffffffffffffffffffffe"}
5 ParseCIDR("abcd:2345::/65") = abcd:2345::, {abcd:2345::, "ffffffffffffffff8000000000000000"}
6 ParseCIDR("abcd:2345::/64") = abcd:2345::, {abcd:2345::, "ffffffffffffffff0000000000000000"}
7 ParseCIDR("abcd:2345::/63") = abcd:2345::, {abcd:2345::, "fffffffffffffffe0000000000000000"}
8 ParseCIDR("abcd:2345::/33") = abcd:2345::, {abcd:2345::, "ffffffff800000000000000000000000"}
9 ParseCIDR("abcd:2345::/32") = abcd:2345::, {abcd:2345::, "ffffffff000000000000000000000000"}
10 ParseCIDR("abcd:2344::/31") = abcd:2344::, {abcd:2344::, "fffffffe000000000000000000000000"}
11 ParseCIDR("abcd:2300::/24") = abcd:2300::, {abcd:2300::, "ffffff00000000000000000000000000"}
12 ParseCIDR("abcd:2345::/24") = abcd:2345::, {abcd:2300::, "ffffff00000000000000000000000000"}
13 ParseCIDR("2001:DB8::/48") = 2001:db8::, {2001:db8::, "ffffffffffff00000000000000000000"}
14 ParseCIDR("2001:DB8::1/48") = 2001:db8::1, {2001: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(172, 16, 1, 1), &net.IPNet{IP: net.IPv4(172, 16, 0, 0), Mask: net.CIDRMask(12, 32)}, true},
    {net.IPv4(172, 24, 0, 1), &net.IPNet{IP: net.IPv4(172, 16, 0, 0), Mask: net.CIDRMask(13, 32)}, false},
    {net.IPv4(192, 168, 0, 3), &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(0, 0, 255, 252)}, true},
    {net.IPv4(192, 168, 0, 4), &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(0, 255, 0, 252)}, false},
    {net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:1::"), Mask: net.CIDRMask(47, 128)}, true},
    {net.ParseIP("2001:db8:1:2::1"), &net.IPNet{IP: net.ParseIP("2001:db8:2::"), Mask: net.CIDRMask(47, 128)}, 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/12
network is : ip+net
string is : 172.16.0.0/13
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 : 2001:db8:1::/47
network is : ip+net
string is : 2001:db8:2::/47
network is : ip+net
string is : 2001:db8:1::/ffff0000ffff00000000000000000000
network is : ip+net
string is : 2001:db8:1::/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(1)
    }
}

func main() {
    if len(os.Args) != 2 {
        fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
        os.Exit(1)
    }
    service := os.Args[1]
    tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
    checkError(1, err)

    //建立一個TCP鏈接conn
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    checkError(2, err)

    //經過conn來發送請求信息
    _, err = conn.Write([]byte("HEAD / HTTP/1.0 \r\n\r\n"))
    checkError(3, err)


    //從conn中讀取服務端返回的所有的文本
    rsp := make([]byte, 64)
    n, err := conn.Read(rsp)
    checkError(4, err)
    fmt.Printf("receive %d bytes in response : %q\n", n, rsp[:n])

    os.Exit(0)
}

服務端爲:

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(1)
    }
}

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:1200
receive 51 bytes in response : "2019-02-27 15:25:02.113373 +0800 CST m=+5.168778770"

 

3)實現UDP Socket — UDPConnUDPAddr

 

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(1)
    }
}

func main() {
    if len(os.Args) != 2 {
        fmt.Fprintf(os.Stderr, "Usage: %s host:port", os.Args[0])
        os.Exit(1)
    }
    service := os.Args[1]
    udpAddr, err := net.ResolveUDPAddr("udp", service)
    checkError(1, err)

    //建立一個TCP鏈接conn
    conn, err := net.DialUDP("udp", nil, udpAddr)
    defer conn.Close()
    checkError(2, err)

    //經過conn來發送請求信息
    _, err = conn.Write([]byte("anything"))
    checkError(3, err)

    //從conn中讀取服務端返回的所有的文本
    var rsp [512]byte
    n, err := conn.Read(rsp[0:])
    checkError(4, err)

    fmt.Printf("receive %d bytes in response : %q\n", n, rsp[:n])
    os.Exit(0)
}

 

服務端

 

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(1)
    }
}

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 [512]byte
    _, addr, err := conn.ReadFromUDP(rsp[0:])
    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:11200
receive 51 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, 1, 2)},
    {"127.0.0.1", net.IPv4(127, 0, 0, 1)},
    {"127.001.002.003", net.IPv4(127, 1, 2, 3)},
    {"::ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"::ffff:127.001.002.003", net.IPv4(127, 1, 2, 3)},
    {"::ffff:7f01:0203", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0:0000:ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0:000000:ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},
    {"0:0:0:0::ffff:127.1.2.3", net.IPv4(127, 1, 2, 3)},

    {"2001:4860:0:2001::68", net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
    {"2001:4860:0000:2001:0000:0000:0000:0068", net.IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 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) != 1 || addrs[0] != 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) != 1 || !reflect.DeepEqual(ips[0], 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
0 LookupHost() addrs is : [127.0.1.2]
0 LookupIP() ips is : [127.0.1.2]
1 LookupHost() addrs is : [127.0.0.1]
1 LookupIP() ips is : [127.0.0.1]
2 LookupHost() addrs is : [127.001.002.003]
2 LookupIP() ips is : [127.1.2.3]
3 LookupHost() addrs is : [::ffff:127.1.2.3]
3 LookupIP() ips is : [127.1.2.3]
4 LookupHost() addrs is : [::ffff:127.001.002.003]
4 LookupIP() ips is : [127.1.2.3]
5 LookupHost() addrs is : [::ffff:7f01:0203]
5 LookupIP() ips is : [127.1.2.3]
6 LookupHost() addrs is : [0:0:0:0:0000:ffff:127.1.2.3]
6 LookupIP() ips is : [127.1.2.3]
7 LookupHost() addrs is : [0:0:0:0:000000:ffff:127.1.2.3]
7 LookupIP() ips is : [127.1.2.3]
8 LookupHost() addrs is : [0:0:0:0::ffff:127.1.2.3]
8 LookupIP() ips is : [127.1.2.3]
9 LookupHost() addrs is : [2001:4860:0:2001::68]
9 LookupIP() ips is : [2001:4860:0:2001::68]
10 LookupHost() addrs is : [2001:4860:0000:2001:0000:0000:0000:0068]
10 LookupIP() ips is : [2001:4860:0:2001::68]

 

func LookupAddr

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

LookupAddr查詢某個地址,返回映射到該地址的主機名序列,本函數和LookupHost不互爲反函數。

 

 未完待續

相關文章
相關標籤/搜索