Go学习-Day10
- 个人博客:CSDN博客
反射
-
编写函数适配器,序列化和反序列话可以用到
-
反射可以在运行时,动态获取变量的各种信息,例如类型,结构体本身的信息,修改变量的值,调用关联的方法
-
反射是不是和映射相反?是一种逆函数?
-
变量到空接口相互转换,空接口和reflect.value相互转换
-
动手一下
-
import ( "fmt" "reflect" ) func test(a interface{}) { b := reflect.TypeOf(a) fmt.Println(b) } func main() { var a int = 10 test(a) }
-
打印 “int”
-
reflect.TypeOf()//从接口获取原类型 reflect.ValueOf()//从接口获取reflect.Value类型.Int能取到具体的类型 //如果需要原类型,需要类型断言 reflect.Interface//把reflect.Value转换成空接口
-
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()//为指针申请空间,可以通过反射来创建类型
网络编程
- 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) } //起一个协程为客户端服务 } }
-
用telnet呼叫一下 telnet 127.0.0.1 8888
-
开始监听 等待连接... con= &{{0xc00010ec80}} 等待连接... //返回
客户端
-
conn, err := net.Dial("tcp", "ip...:端口") //获取连接 //Dial是拨号的意思
-
通过端口就能和对应的程序进行交流
-
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}}
发送&&接收
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)
}
}
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)
}
- 一个小点,发送的字节数多2,应该是回车键的缘故,可能这里是当成\n\r