二、net包的使用

net包使用

net包主要是围绕三大数据类型做衍生的,如下:
type Addr
type Listener
type Conn

1、Listen函数

返回在一个本地网络地址laddr上监听的Listener。网络类型参数net必须是面向流的网络:"tcp"、"tcp4"、"tcp6"、"unix"或"unixpacket",因为是在服务器端使用,必须建立连接,面向包的udp是无连接的,所以listen函数net参数不支持udp。参见Dial函数获取laddr的语法

func Listen(network, address string) (Listener, error) {
    addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", network, address, nil)
    if err != nil {
        return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
    }
    var l Listener
    switch la := addrs.first(isIPv4).(type) {
    case *TCPAddr:
        l, err = ListenTCP(network, la)
    case *UnixAddr:
        l, err = ListenUnix(network, la)
    default:
        return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
    }
    if err != nil {
        return nil, err // l is non-nil interface containing nil pointer
    }
    return l, nil
}

Listen函数用于获取一个监听器,相当与一个包装以下三个函数的函数 :

socket()
bind()
listen()

2、Accept方法

Accept方法属于net.Listener类型的方法,在调用时流程会阻塞,直到某个计算机上的某个应用程序与当前程序建立了一个tcp连接。此时accept方法会返回连个值,一个net.Conn类型值,一个error类型值

Accept() (Conn, error)

3、client 端函数 Dial函数和 DialTimeout函数

在网络network上连接地址address,并返回一个Conn接口。可用的网络类型有:"tcp"、"tcp4"、"tcp6"、"udp"、"udp4"、"udp6"、"ip"、"ip4"、"ip6"、"unix"、"unixgram"、"unixpacket"
对TCP和UDP网络,地址格式是host:port或[host]:port,参见函数JoinHostPort和SplitHostPort
等价于一个包装以下三个函数的函数:

socket()
bind()
connect

函数原型:

func Dial(network, address string) (Conn, error)
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)

4、Conn类型

Conn接口代表通用的面向流的网络连接。多个线程可能会同时调用同一个Conn的方法。

type Conn interface {
    // Read从连接中读取数据
    // Read方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Read(b []byte) (n int, err error)
    // Write从连接中写入数据
    // Write方法可能会在超过某个固定时间限制后超时返回错误,该错误的Timeout()方法返回真
    Write(b []byte) (n int, err error)
    // Close方法关闭该连接
    // 并会导致任何阻塞中的Read或Write方法不再阻塞并返回错误
    Close() error
    // 返回本地网络地址
    LocalAddr() Addr
    // 返回远端网络地址
    RemoteAddr() Addr
    // 设定该连接的读写deadline,等价于同时调用SetReadDeadline和SetWriteDeadline
    // deadline是一个绝对时间,超过该时间后I/O操作就会直接因超时失败返回而不会阻塞
    // deadline对之后的所有I/O操作都起效,而不仅仅是下一次的读或写操作
    // 参数t为零值表示不设置期限
    SetDeadline(t time.Time) error
    // 设定该连接的读操作deadline,参数t为零值表示不设置期限
    SetReadDeadline(t time.Time) error
    // 设定该连接的写操作deadline,参数t为零值表示不设置期限
    // 即使写入超时,返回值n也可能>0,说明成功写入了部分数据
    SetWriteDeadline(t time.Time) error
}

4、Read方法

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

5、Write方法

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

6、Close方法

func (c *TCPConn) Close() error

7、LocalAddr 和 RemoteAddr方法

func (c *TCPConn) LocalAddr() Addr //LocalAddr返回本地网络地址
func (c *TCPConn) RemoteAddr() Addr //RemoteAddr返回远端网络地址

8、SetDeadline、SetReadDeadline、SetWriteDeadline

func (c *TCPConn) SetDeadline(t time.Time) error //SetDeadline设置读写操作期限,实现了Conn接口的SetDeadline方法
func (c *TCPConn) SetReadDeadline(t time.Time) error //SetReadDeadline设置读操作期限,实现了Conn接口的SetReadDeadline方法
unc (c *TCPConn) SetWriteDeadline(t time.Time) error //SetWriteDeadline设置写操作期限,实现了Conn接口的SetWriteDeadline方法

9、ParseIP函数将string类型的ip地址转换为IP对象

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

type IPMask []byte //IPMask代表一个IP地址的掩码

代码事例:

package main

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

func main(){
    ipS := "192.168.1.97"
    //将字符串解析为ip地址,并返回并返回该地址,如果s不是合法的IP地址文本表示,ParseIP会返回nil
    ip := net.ParseIP(ipS)
    if ip == nil {
        fmt.Fprintf(os.Stderr, "ipS err: 地址是无效的 \n")
    }
    fmt.Print(ip , "\n")

    //根据IP和掩码获得网络
    mask := ip.DefaultMask()

    network := ip.Mask(mask)
    fmt.Printf("ip: %s, mask: %s, network: %s \n", ip, mask.String(), network.String())
}

10、将域名解析为ip地址

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

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

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

代码事例:

domain := "www.baidu.com:8080"
addr, err := net.ResolveTCPAddr("tcp", domain)
if err != nil {
    fmt.Printf("err: %s", err)
    return
}
fmt.Print(addr)

11、使用案例

服务端 service:

package main

import (
    "net"
    "log"
    "io/ioutil"
    "fmt"
)

func clientHandler(conn net.Conn) {
    defer conn.Close()

    //向客户端读取数据
    params, err := ioutil.ReadAll(conn)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Print(string(params))

    //向客户端发送数据
    n, err := conn.Write([]byte("hello,client \r\n"))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Print(n)
}

func main()  {
    listen, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }
    for {
        conn, err := listen.Accept()
        if err != nil {
            fmt.Print(err)
            continue
        }
        go clientHandler(conn)
    }

}

客户端 client:

package main

import (
    "net"
    "log"
    "io/ioutil"
    "fmt"
)

func main() {
    conn, err := net.Dial("tcp", ":8080")
    if err != nil {
        log.Fatal(err)
    }

    //向服务器发送数据
    n, err := conn.Write([]byte("GET / HTTP/1.1 \r\n\r\n"))
    if err != nil {
        log.Fatal(err)
    }

    //向服务器读取数据
    res, err := ioutil.ReadAll(conn)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("response: %s, write byte num: %d", string(res), n)
    conn.Close()
}

你可能感兴趣的:(二、net包的使用)