[Go-lang] net包

序:契机

  • 因近期产线 opengemini 频繁出问题,为此不得不研究 gemini 的源代码。

: opengemini : lib/machine/id.go#parseAddr

https://github.com/openGemini/openGemini/blob/main/lib/machine/id.go

# tailf /usr/local/opengemini/gemini-log/logs/ts-sql-8086/sql.log
...
{"level":"warn","time":"2024-12-23T13:36:42.960522422+08:00","msg":"failed to parse address","hostname":"vmw-b.severs.com:8086","error":"invalid address: vmw-b.severs.com:8086","location":"machine/id.go:44","repeated":1}
...

核心API

func SplitHostPort(hostport string) (host, port string, err error)

  • 函数功能

将格式为”host:port”、”[host]:port”或”[ipv6-host%zone]:port”的网络地址分割为host或ipv6-host%zone和port两个部分。

  • 使用案例: opengemini : lib/machine/id.go#parseAddr

https://github.com/openGemini/openGemini/blob/main/lib/machine/id.go

func parseAddr(addr string) (net.IP, uint64, error) {
	host, port, err := net.SplitHostPort(addr) // 入参 addr := "vmw-b.severs.com:8086" | 出参 host, port, err := vmw-b.severs.com , 8086 , nil <nil>
	if err != nil {
		return nil, 0, err
	}

	ip := net.ParseIP(host)//入参 host = "vmw-b.severs.com"
	if len(ip) != net.IPv6len {
		return nil, 0, errno.NewError(errno.InvalidAddress, addr)
	}

	ip = ip[net.IPv6len-4:]
	if binary.BigEndian.Uint32(ip) == 0 {
		return nil, 0, errno.NewError(errno.BadListen, addr)
	}

	p, _ := strconv.ParseUint(port, 10, 64)
	return ip, p, nil
}

等效实验:

package main

import (
    "fmt"
    "os"
    "net"
)

func main()  {
    addr := "vmw-b.severs.com:8086";
    host, port, err := net.SplitHostPort(addr);
    fmt.Println("host, port, err:", host, port, err);//host, port, err: vmw-b.severs.com 8086 <nil>
	ip := net.ParseIP(host); //入参 host = "vmw-b.severs.com" (错误的入参) | 出参 ip = <nil>
}

func ParseIP(s string) IP

ParseIP parses s as an IP address, returning the result. The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. If s is not a valid textual representation of an IP address, ParseIP returns nil. The returned address is always 16 bytes, IPv4 addresses are returned in IPv4-mapped IPv6 form. ParseIP将解析为IP地址,并返回结果。字符串s可以是IPv4点分十进制(“192.0.2.1”)、IPv6(“2001:db8::68”)或IPv4映射IPv6(“::ffff:192.0.2.1””)形式。 如果s不是IP地址的有效文本表示,ParseIP将返回nil`。
返回的地址始终为16个字节,IPv4地址以IPv4映射的IPv6形式返回。

func JoinHostPort(host, port string) string

  • 函数功能

将host和port合并为一个网络地址。一般格式为”host:port”;如果host含有冒号或百分号,格式为”[host]:port”。

type HardwareAddr []byte

  • HardwareAddr类型代表一个硬件地址(MAC地址)

func ParseMAC(s string) (hw HardwareAddr, err error)

  • 函数功能

ParseMAC函数使用如下格式解析一个IEEE 802 MAC-48、EUI-48或EUI-64硬件地址:

01:23:45:67:89:ab
01:23:45:67:89:ab:cd:ef
01-23-45-67-89-ab
01-23-45-67-89-ab-cd-ef
0123.4567.89ab
0123.4567.89ab.cdef

func (a HardwareAddr) String() string

网卡的状态标识

type Flags uint
const (
    FlagUp           Flags = 1 << iota // 接口在活动状态  1
    FlagBroadcast                      // 接口支持广播    2 
    FlagLoopback                       // 接口是环回的    4
    FlagPointToPoint                   // 接口是点对点的  8 可以理解为单播
    FlagMulticast                      // 接口支持组播    16 和多播同义
)
var flagNames = []string{
   "up",
   "broadcast",
   "loopback",
   "pointtopoint",
   "multicast",
}

func (f Flags) String() string

网卡的相关的方法

type Interface struct {
    Index        int          // 索引,>=1的整数
    MTU          int          // 最大传输单元
    Name         string       // 接口名,例如"en0"、"lo0"、"eth0.100"
    HardwareAddr HardwareAddr // 硬件地址,IEEE MAC-48、EUI-48或EUI-64格式
    Flags        Flags        // 接口的属性,例如FlagUp、FlagLoopback、FlagMulticast
}

func Interfaces() ([]Interface, error)

  • Interfaces返回该系统的网络接口列表。

例如:(输出结果为了现实方便,使用json输出)

[
  {
    "Index": 1,
    "MTU": 16384,
    "Name": "lo0",
    "HardwareAddr": null,
    "Flags": 21 //相当于 up|loopback|multicast ,网卡使用中,支持环回、组播
  },
  {
    "Index": 9,
    "MTU": 1484,
    "Name": "awdl0",
    "HardwareAddr": "yvQEMXJ1",
    "Flags": 18 //相当于broadcast|multicast,网卡未使用,支持广播、组播
  },
  {
    "Index": 5,
    "MTU": 1500,
    "Name": "en4",
    "HardwareAddr": "aFs1niJI",
    "Flags": 19 //相当于 up|broadcast|multicast,网卡使用中,支持广播、组播
  }
]

func InterfaceByIndex(index int) (*Interface, error)

  • InterfaceByIndex返回指定索引的网络接口。

例如

interfaces,_ := net.InterfaceByIndex(5)
json , _ := json.Marshal(interfaces)

输出:
{
  "Index": 5,
  "MTU": 1500,
  "Name": "en4",
  "HardwareAddr": "aFs1niJI",
  "Flags": 19
}

func InterfaceByName(name string) (*Interface, error)

  • InterfaceByName返回指定名字的网络接口
interfaces,_ := net.InterfaceByName("awdl0")
json , _ := json.Marshal(interfaces)

输出:
{
  "Index": 9,
  "MTU": 1484,
  "Name": "awdl0",
  "HardwareAddr": "yvQEMXJ1",
  "Flags": 18
}

func (ifi *Interface) Addrs() ([]Addr, error)

Addrs方法返回网络接口ifi的一或多个接口地址。

inter,_ := net.InterfaceByIndex(5)
addrs, _ := inter.Addrs()
fmt.Println(addrs)

输出:
[fe80::6a5b:35ff:fe9e:2248/64 10.1.81.38/23]

func (ifi *Interface) MulticastAddrs() ([]Addr, error)

MulticastAddrs返回网络接口ifi加入的多播组地址。

inter,_ := net.InterfaceByIndex(5)
addrs, _ := inter.MulticastAddrs()
json , _ := json.Marshal(addrs)
fmt.Fprintf(c.Writer, string(json))

输出:
[
  {
    "IP": "224.0.0.251",
    "Zone": ""
  }, {
    "IP": "ff02::fb",
    "Zone": ""
  },{
    "IP": "224.0.0.1",
    "Zone": ""
  },{
    "IP": "ff01::1",
    "Zone": ""
  }, {
    "IP": "ff02::2:ff4d:9ef2",
    "Zone": ""
  }, {
    "IP": "ff02::1",
    "Zone": ""
  }, {
    "IP": "ff02::1:ff9e:2248",
    "Zone": ""
  }]

网络终端

type Addr interface {
    Network() string // 网络名
    String() string  // 字符串格式的地址
}

X 参考文献

  • go

https://github.com/openGemini/openGemini/blob/main/app/ts-sql/sql/server.go

[root@vmw-d ~]# tailf /usr/local/opengemini/gemini-log/logs/ts-sql-8086/sql.log
{"level":"error","time":"2024-12-23T10:23:06.166984231+08:00","caller":"transport/node.go:52","msg":"dial failed","hostname":"vmw-d.servers.com:8086","error":"dial tcp [::1]:8092: connect: connection refused"}
{"level":"error","time":"2024-12-23T10:23:08.171332623+08:00","caller":"transport/node.go:52","msg":"dial failed","hostname":"vmw-d.servers.com:8086","error":"dial tcp 192.168.101.103:8092: connect: connection refused"}
{"level":"error","time":"2024-12-23T10:23:09.172203321+08:00","caller":"transport/node.go:52","msg":"dial failed","hostname":"vmw-d.servers.com:8086","error":"dial tcp [::1]:8092: connect: connection refused"}
{"level":"error","time":"2024-12-23T10:23:11.179264372+08:00","caller":"transport/node.go:52","msg":"dial failed","hostname":"vmw-d.servers.com:8086","error":"dial tcp 192.168.101.103:8092: connect: connection refused"}
{"level":"error","time":"2024-12-23T10:23:12.180383605+08:00","caller":"transport/node.go:52","msg":"dial failed","hostname":"vmw-d.servers.com:8086","error":"dial tcp [::1]:8092: connect: connection refused"}
{"level":"info","time":"2024-12-23T10:24:43.435184457+08:00","caller":"syscontrol/syscontrol.go:153","msg":"DisableWrites","switch":false}
{"level":"info","time":"2024-12-23T10:24:43.436841617+08:00","caller":"syscontrol/syscontrol.go:158","msg":"DisableReads","switch":false}
{"level":"info","time":"2024-12-23T10:24:43.442235127+08:00","caller":"app/common.go:287","msg":"TSSQL starting","hostname":"vmw-d.servers.com:8086","version":"v1.2.0","branch":"HEAD","commit":"eb398291ee88b7dde94f431a830e04544bd47e1f","buildTime":"2024-02-29T09:33:29Z"}
{"level":"info","time":"2024-12-23T10:24:43.442277713+08:00","caller":"app/common.go:292","msg":"Go runtime","hostname":"vmw-d.servers.com:8086","version":"go1.21.7","maxprocs":1}
{"level":"warn","time":"2024-12-23T10:24:46.403076232+08:00","msg":"failed to parse address","hostname":"vmw-d.servers.com:8086","error":"invalid address: vmw-d.servers.com:8086","location":"machine/id.go:44","repeated":1}
posted @ 2024-12-23 14:10  千千寰宇  阅读(70)  评论(0)    收藏  举报