• Go 标准库 net



    本篇文章主要介绍 Go 标准库中的 net 包,通过一个小例子介绍常用的 net 包函数/方法 Listen,Accept 和 Dial 等。

    1. net 简介

    Go 官网对 net 包的定义如下:

    Package net provides a portable interface for network I/O, including TCP/IP, UDP, domain name resolution, and Unix domain sockets.
    

    net 包的常用方法有 Listen, Accept 和 Dial 等。下面通过一段代码将他们组合起来:

    package main
    
    import (
    	"fmt"
    	"net"
    	"sync"
    )
    
    var wg sync.WaitGroup
    
    func serverAccept(l net.Listener) {
    	defer wg.Done()
    	ln, err := l.Accept()
    	if err != nil {
    		fmt.Printf("accept error")
    		return
    	}
    
    	recData := make([]byte, 1024)
    	len, err := ln.Read(recData)
    
    	fmt.Printf("len: %d
    ", len)
    	fmt.Printf("rec Data: %v
    ", string(recData[:len]))
    
    	sendData := []byte("hello, client")
    	ln.Write(sendData)
    }
    
    func main() {
    	// server emulator
    	l, err := net.Listen("tcp", ":0")
    	if err != nil {
    		fmt.Printf("listen error")
    		return
    	}
    
    	wg.Add(1)
    	go serverAccept(l)
    
    	// client emulator
    	addr := l.Addr().String()
    	cn, err := net.Dial("tcp", addr)
    	if err != nil {
    		fmt.Printf("Dial error")
    		return
    	}
    
    	data := []byte("hello, server")
    	cn.Write(data)
    
    	recDataClient := make([]byte, 1024)
    	len, err := cn.Read(recDataClient)
    	fmt.Printf("recDataClient: %v", string(recDataClient[:len]))
    
    	wg.Wait()
    }
    

    这段代码实现了一个 server emulator 和 client emulator,client 发送 hello, server 给 server,server 再返回 hello, client 给 client。查看代码执行结果:

    len: 13
    rec Data: hello, server
    recDataClient: hello, client
    

    下面介绍代码使用到的 net 包函数/方法。

    1.1 net.Listen

    调用 Listen 将使 server 侦听在网络地址上。Listen 是 net 包中的函数,它的输入是 network 和 address,返回值是接口类型 Listener:

    func Listen(network, address string) (Listener, error) {
    	var lc ListenConfig
    	return lc.Listen(context.Background(), network, address)
    }
    

    查看 Listener 的定义:

    type Listener interface {
    	// Accept waits for and returns the next connection to the listener.
    	Accept() (Conn, error)
    
    	// Close closes the listener.
    	// Any blocked Accept operations will be unblocked and return errors.
    	Close() error
    
    	// Addr returns the listener's network address.
    	Addr() Addr
    }
    

    它包括三种方法 Accept,Close 以及 Addr。查看 Accept 方法如下:

    1.2 Listener.Accept

    查看官网对 Accept 方法的定义:

    Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn.
    

    它有两种原型:

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

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

    Accept 的指针接收者为 TCPListener,代码中调用 Accept 的是接口类型 Listener。所以应该发生了 TCPListener 到接口类型的转换,转换过程就发生在 lc.Listen(...) 函数里,查看该函数:

    func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (Listener, error) {
        ...
        var l Listener
            la := addrs.first(isIPv4)
            switch la := la.(type) {
            case *TCPAddr:
                l, err = sl.listenTCP(ctx, la)
            case *UnixAddr:
                l, err = sl.listenUnix(ctx, la)
        ...
    }
    
    func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
    	...
    }
    

    发现方法 listenTCP,listenUnix 做了接口类型的转换。

    1.3 net.Dial

    client 调用 Dial 函数和 server 建立连接,Dial 返回 Conn 接口类型。

    func Dial(network, address string) (Conn, error) {
    	var d Dialer
    	return d.Dial(network, address)
    }
    

    1.4 Conn

    Conn 是一种接口类型,查看它的定义:

    type Conn interface {
    	// Read reads data from the connection.
    	// Read can be made to time out and return an error after a fixed
    	// time limit; see SetDeadline and SetReadDeadline.
    	Read(b []byte) (n int, err error)
    
    	// Write writes data to the connection.
    	// Write can be made to time out and return an error after a fixed
    	// time limit; see SetDeadline and SetWriteDeadline.
    	Write(b []byte) (n int, err error)
    
    	// Close closes the connection.
    	// Any blocked Read or Write operations will be unblocked and return errors.
    	Close() error
    
    	LocalAddr() Addr
    
    	RemoteAddr() Addr
    
    	SetDeadline(t time.Time) error
    
    	SetReadDeadline(t time.Time) error
    
    	SetWriteDeadline(t time.Time) error
    }
    

    代码中使用到了接口的 Read 和 Write 方法,它的功能如注释所示。其中 Read 和 Write 的入参是字节切片。

    1.5 字节切片 []byte

    Go 中定义了字节切片,字符切片的特性如下:

    1. 一个字符串是一个不可改变的字节序列
    2. 文本字符串通常被解释为采用UTF8编码的Unicode码点(rune)序列
    3. 内置的len函数可以返回一个字符串中的字节数目
    4. 第i个字节并不一定是字符串的第i个字符,因为对于非ASCII字符的UTF8编码会要两个或多个字节
    5. 字符串操作基于原始字符串字节
    6. 字符串面值方式编写,只要将一系列字节序列包含在双引号内即可,解释字符串,其中的相关的转义字符将被替换;反引号括起来,支持换行,非解释字符串
    7. 每个符号都分配一个唯一的Unicode码点,Unicode码点对应Go语言中的rune整数类型
    8. UTF8是一个将Unicode码点编码为字节序列的变长编码
    9. 变长的编码无法直接通过索引来访问第n个字符
    10. 将字符串看作是字节(byte)的切片(slice)来实现对其标准索引法的操作

    参考: https://cloud.tencent.com/developer/article/1501644

    芝兰生于空谷,不以无人而不芳。
  • 相关阅读:
    记中兴软件园一个月实训(四)
    MMORPG大型游戏设计与开发(服务器 AI 逻辑设定和状态结点)
    MMORPG大型游戏设计与开发(服务器 AI 事件)
    MMORPG大型游戏设计与开发(服务器 AI 控制器)
    MMORPG大型游戏设计与开发(服务器 AI 基础接口)
    MMORPG大型游戏设计与开发(服务器 AI 概述)
    MMORPG大型游戏设计与开发(服务器 游戏场景 动态场景与副本)
    MMORPG大型游戏设计与开发(服务器 游戏场景 掉落与网络连接)
    MMORPG大型游戏设计与开发(服务器 游戏场景 搜索机)
    MMORPG大型游戏设计与开发(服务器 游戏场景 聊天管道和寻路器)
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/14691736.html
Copyright © 2020-2023  润新知