加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

Golang学习之net包介绍

发布时间:2020-12-16 18:05:04 所属栏目:大数据 来源:网络整理
导读:与大多数语言一样,Go的标准库很全,因为Go的出现本来就是为了网络通信的高并发实现,所以其相关的网络库封装得更简洁,更Readable。 这里来大致介绍几个网络库,掌握了学习方法,那么只要里面有那个功能,你就能找到并快读查阅源码,了解其实现。 net.Resol

与大多数语言一样,Go的标准库很全,因为Go的出现本来就是为了网络通信的高并发实现,所以其相关的网络库封装得更简洁,更Readable。

这里来大致介绍几个网络库,掌握了学习方法,那么只要里面有那个功能,你就能找到并快读查阅源码,了解其实现。
net.ResolveIPAddr()

根据域名查找IP地址

不得不感叹Go为开发者考虑良多,godoc这个工具真的很方便!先看下源码。

$ godoc -src net.ResolveIPAddr
func ResolveIPAddr(net,addr string) (*IPAddr,error) {
    if net == "" {
        net = "ip"
    }
    afnet,_,err := parseNetwork(net)
    if err != nil {
        return nil,err
    }
    switch afnet {
    case "ip","ip4","ip6":
    default:
        return nil,UnknownNetworkError(net)
    }
    addrs,err := internetAddrList(afnet,addr,noDeadline)
    if err != nil {
        return nil,err
    }
    return addrs.first(isIPv4).(*IPAddr),nil
}

我们又从源码中学习了一招:case "ip","ip4","ip6"。switch的一个case直接检测多个值的方法,如果不匹配则执行default中的代码。

可以看到,net和addr形参都接受string类型,而返回IPAddr的指针类型,和error类型的值。

来使用一下:

package main

import (
    "fmt"
    "net"
)

func main() {
    addr,err := net.ResolveIPAddr("ip","www.baidu.com")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(addr.IP)

输出:

注意看ResolveIPAddr的源码,如果你传给net的参数不是”ip”,“ip4”,“ip6”其中的一个,那么err就不会是nil,而是UnknownNetworkError(net),错误的输出信息会是这样的:
unknown network tcp

net.ParseIP()

检查IP地址格式是否有效

依照惯例,我们来看一下源码,$ godoc -src net ParseIP

func ParseIP(s string) IP {
    for i := 0; i < len(s); i++ {
        switch s[i] {
        case '.':
            return parseIPv4(s)
        case ':':
            ip,_ := parseIPv6(s,false)
            return ip
        }
    }
    return nil
}

IPv4用.号隔开,IPv6用号隔开,所以这个函数的内部又进行了判断其是IPv4还是IPv6。

注意:你不要手动去调用net.parseIPv4或者net.parseIPv6,会报如下错误:

cannot refer to unexported name net.parseIPV4
undefined: net.parseIPV4

因为Go利用首字母的大小写来限制包外是否可访问,小写的函数或变量在包外无法访问到,就如同Java的public,private修饰符。不过用godoc来获取小写开头的源码是没有问题的。

查看parseIPv4的源码又发现:

func parseIPv4(s string) IP {
    // ...
    return IPv4(p[0],p[1],p[2],p[3])
}

再追溯到IPv4上

func IPv4(a,b,c,d byte) IP { p := make(IP,IPv6len) copy(p,v4InV6Prefix) p[12] = a p[13] = b p[14] = c p[15] = d return p }

我们发现这些函数都返回了IP对象,我们来看一下IP对象的定义:

type IP []byte 

其实就是一个自定义的数组切片类型。

IPv4内部用make初始化了一个数组切片,并且指定了元素个数为IPv6len。IPv6len被定义为常量:

const ( IPv6len = 16 )

然后进行将v4InV6Prefix复制到到数组切片p中,copy的用法请自行搜索(注意copy的行为和常人的理解不同):

var v4InV6Prefix = []byte{0,0,0xff,0xff}

至于储存IPv4的数组切片为什么要分配16个元素的大小,又复制给最后四个索引,可以看type IP []byte的注释:

// An IP is a single IP address,a slice of bytes.
// Functions in this package accept either 4-byte (IPv4)
// or 16-byte (IPv6) slices as input.
//
// Note that in this documentation,referring to an
// IP address as an IPv4 address or an IPv6 address
// is a semantic property of the address,not just the
// length of the byte slice: a 16-byte slice can still
// be an IPv4 address.
type IP []byte

这说了,一个16-byte大小的数组可以仍然作为IPv4地址。创建数组切片slice1 := make([]int,5)其初始值都为0。

Go的源码不难,甚至比C简单,而且标准库的设计也非常规范。如果你需要使用更多的功能,可以查看net包的文档。

转自:http://www.52php.cn/article/p-reusqfyy-bcg.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读