• # Go学习-Day10


    Go学习-Day10

    反射

    • 编写函数适配器,序列化和反序列话可以用到

    • 反射可以在运行时,动态获取变量的各种信息,例如类型,结构体本身的信息,修改变量的值,调用关联的方法

    • 反射是不是和映射相反?是一种逆函数?

    • 变量到空接口相互转换,空接口和reflect.value相互转换

    • 动手一下

    • import (
      	"fmt"
      	"reflect"
      )
      
      func test(a interface{}) {
      	b := reflect.TypeOf(a)
      	fmt.Println(b)
      }
      
      func main() {
      	var a int = 10
      	test(a)
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
    • 打印 “int”

    • reflect.TypeOf()//从接口获取原类型
      reflect.ValueOf()//从接口获取reflect.Value类型.Int能取到具体的类型
      //如果需要原类型,需要类型断言
      reflect.Interface//把reflect.Value转换成空接口
      
      • 1
      • 2
      • 3
      • 4
    • Kind是大的种类,Type是小的类型

    • 常量在定义的时候必须初始化

    • reflect.Value.Kind返回的是常量

    • 如果传入指针类型的话(反射常常需要改变原来的值)指针类型需要.Elem方法取到值,再用.SetInt之类的方修改原来的值

    • Value//指reflect.Value
      Value.NumField()//获取字段数
      Value.Field()//根据下标,获取第几个字段,返回的也是relect.Value
      Tpye//指reflect.Type
      Tpye.Field().Tag.Get("key")//可以获取tag,键值是结构体里面设置的例如,"json:"的key就是json,序列化反序列化的键值固定取json,其实可以自定义
      Value.NumMethod()//获取方法数
      Value.Method().Call(...)//获取第几个方法,然后调用
      //这个顺序是按照函数名字典序排列的,Call传的是Value切片,返回的也是Value切片
      //输入的时候需要定义一个Value切片,用reflect.ValueOf(xx)插入这个切片
      Value.Elem().Field().SetXxx//修改字段
      ...FieldByName()//可以用字段名来找
      Value.New()//为指针申请空间,可以通过反射来创建类型
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    网络编程

    • Golang的主要设计目标之一就是面向大规模的后端服务程序,网络通信是服务端程序必不可少的一部分
    • 网络编程有两种 TCP(Transmission Control Protocol) socket编程和HTTP编程(建立在前者之上)
    • 做服务器尽量少开端口,一个端口只能被一个程序监听

    监听端口小Demo

    • net包提供了可以指的I/O接口

    • package main
      
      import (
      	"fmt"
      	"net"
      )
      
      func main() {
      
      	fmt.Println("开始监听")
      	//使用tcp协议,监听本机
      	listen, err := net.Listen("tcp", "0.0.0.0:8888")
      	if err != nil {
      		fmt.Println("err=", err)
      	}
      	//延迟关闭
      	defer listen.Close()
      	//循环等待
      	for {
      		//等待客户端连接
      		fmt.Println("等待连接...")
      		//获取连接
      		conn, err := listen.Accept()
      		if err != nil {
      			fmt.Println("err=", err)
      		} else {
      			fmt.Println("con=", conn)
      		}
      		//起一个协程为客户端服务
      	}
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
    • 用telnet呼叫一下 telnet 127.0.0.1 8888

    • 开始监听
      等待连接...
      con= &{{0xc00010ec80}}
      等待连接...
      //返回
      
      • 1
      • 2
      • 3
      • 4
      • 5

    客户端

    • conn, err := net.Dial("tcp", "ip...:端口")
      //获取连接
      //Dial是拨号的意思
      
      • 1
      • 2
      • 3
    • 通过端口就能和对应的程序进行交流

    • func main() {
      	conn, err := net.Dial("tcp", "127.0.0.1:8888")
      	if err != nil {
      		fmt.Println("err=", err)
      	}
      	fmt.Println("连接成功conn=", conn)
      }
      //注意此时要开着上面的监听程序
      //输出 连接成功conn= &{{0xc00010ca00}}
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    发送&&接收

    server.go

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func process(conn net.Conn) {
    	//连接过多不关闭的话就会导致其他连接无法成功
    	defer conn.Close()
    
    	for {
    		buf := make([]byte, 512)
    		//如果没有Write会停在这里,类似我们stdin输入的时候,光标会停在输入的位置
    		//如果连接突然中断的话,这里会报错
    		//TCP底层会定时发送消息,检查连接是否存在
    		n, err := conn.Read(buf)
    		if err != nil {
    			fmt.Println("err=", err)
    			return
    			//有可能是关闭了
    		}
    		//字节切片要强制转换
    		//buf后面的存的可能是乱七八糟的东西,注意取前n个!
    		fmt.Print(string(buf[:n]))
    
    	}
    }
    
    func main() {
    
    	fmt.Println("开始监听")
    	//使用tcp协议,监听本机
    	listen, err := net.Listen("tcp", "0.0.0.0:8888")
    	if err != nil {
    		fmt.Println("err=", err)
    	}
    	//延迟关闭
    	defer listen.Close()
    	//循环等待
    	for {
    		//等待客户端连接
    		fmt.Println("等待连接...")
    		//获取连接
    		conn, err := listen.Accept()
    		if err != nil {
    			fmt.Println("err=", err)
    		} else {
    			fmt.Println("con=", conn)
    		}
    		//起一个协程为客户端服务
    		go process(conn)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    client.go

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"net"
    	"os"
    )
    
    func main() {
    	conn, err := net.Dial("tcp", "127.0.0.1:8888")
    	if err != nil {
    		fmt.Println("err=", err)
    	}
    	fmt.Println("连接成功conn=", conn)
    
    	//创建标准stdin的reader
    	reader := bufio.NewReader(os.Stdin)
    	//读取一行
    	str, err := reader.ReadString('\n')
    	if err != nil {
    		fmt.Println("err=", err)
    	}
    
    	n, err := conn.Write([]byte(str))
    	if err != nil {
    		fmt.Println("err=", err)
    	}
    	fmt.Println("发送了n个字节n=", n)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 一个小点,发送的字节数多2,应该是回车键的缘故,可能这里是当成\n\r
  • 相关阅读:
    2022年双十一好物分享,数码好物选购指南
    Karmada 多云容器编排引擎支持多调度组,助力成本优化
    非root权限下run qemu-kvm
    C++ Reference: Standard C++ Library reference: C Library: cwchar: fputws
    【小程序源码】看成语猜古诗句好玩解闷小游戏
    Python类和对象创建过程分析与元类以及魔法函数
    手动写一个搜索引擎(超详细)
    c++ makefile + clangd 生成 compile_command.json
    【MySql】mysql之进阶查询语句
    在Linux中安装docker全过程
  • 原文地址:https://blog.csdn.net/gfyy_bkj/article/details/132676405