当前位置: 首页 > news >正文

【启程Golang之旅】网络编程与反射

欢迎来到Golang的世界!在当今快节奏的软件开发领域,选择一种高效、简洁的编程语言至关重要。而在这方面,Golang(又称Go)无疑是一个备受瞩目的选择。在本文中,带领您探索Golang的世界,一步步地了解这门语言的基础知识和实用技巧。

目录

初识网络编程

初识反射


初识网络编程

把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。设备之间在网络中进行数据的传输,发送/接收数据。

网络:两台或者两台以上计算机就可以构成网络,如下图所示:

设备之间进行传输数据的时候,必须遵循一定的通讯协议规则,具体如下所示:

接下来我们就网络通信的流程写一下网络编程实现的过程,如下:

创建客户端:调用Dial函数实现创建客户端,示例代码如下所示:

func main() {// 打印fmt.Println("客户端启动。。。")// 调用Dial函数,参数需要指定tcp协议,需要指定服务器端的IP+PORTcon, err := net.Dial("tcp", "127.0.0.1:8888")if err != nil {fmt.Println("连接失败, err = ", err)} else {// 打印连接成功fmt.Println("连接成功, con = ", con)}
}

创建服务器端:调用Listen函数实现创建服务器端,示例代码如下所示:

func main() {// 打印fmt.Println("服务器端启动。。。")// 进行监听:需要指定服务器端TCP协议,服务器端的IP+PORTlisten, err := net.Listen("tcp", "127.0.0.1:8888")if err != nil {fmt.Println("监听失败, err = ", err)return}// 监听成功,等待客户端的连接// 循环等待客户端的连接for {con, err1 := listen.Accept()if err1 != nil {fmt.Println("等待客户端连接失败, err = ", err1)return} else {// 连接成功fmt.Printf("等待连接成功,con = %v, 接收到的客户端信息:%v \n", con, con.RemoteAddr().String())}}
}

连接测试:接下来我们开始启动我们的客户端和服务器端,这里我们首先启动服务器端,然后启动客户端对服务器端进行访问,服务器端就等待客户端的访问连接即可,画面如下所示:

发送数据:上面演示了客户端与服务器端的连接,接下来我们开始在客户端设置一些数据然后发送给服务器端,让服务器端去接收到客户端发送过来的数据,示例代码如下所示,由于客户端发送一次数据就关闭了,所以服务器端报出客户端的连接意外关闭的err,这个忽视就行。

具体的代码如下所示:

// 客户端
package mainimport ("bufio""fmt""net""os"
)func main() {// 打印fmt.Println("客户端启动。。。")// 调用Dial函数,参数需要指定tcp协议,需要指定服务器端的IP+PORTcon, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("连接失败, err = ", err)} else {// 打印连接成功fmt.Println("连接成功, con = ", con)}// 通过客户端发送单行数据,然后退出reader := bufio.NewReader(os.Stdin) // os.Stdin代表终端标准输入// 从终端读取一行用户输入的信息str, err := reader.ReadString('\n')if err != nil {fmt.Println("终端输入失败, err = ", err)}// 将用户输入的信息发送给服务器端con1, err1 := con.Write([]byte(str)) // []byte将字符串转换为字节数组if err1 != nil {fmt.Println("连接失败, err = ", err1)}// 打印发送成功fmt.Printf("发送成功,发送%d个字节\n", con1)
}// 服务器端
package mainimport ("fmt""net"
)func process(con net.Conn) {// 连接数据完要进行关闭defer con.Close()for {// 创建一个切片,用于接收客户端的数据buf := make([]byte, 1024)// 接收客户端的数据n, err := con.Read(buf)if err != nil {fmt.Println("接收客户端数据失败, err = ", err)return}// 打印接收到的数据fmt.Printf("接收到客户端数据:%v \n", string(buf[0:n]))}
}func main() {// 打印fmt.Println("服务器端启动。。。")// 进行监听:需要指定服务器端TCP协议,服务器端的IP+PORTlisten, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {fmt.Println("监听失败, err = ", err)return}// 监听成功,等待客户端的连接// 循环等待客户端的连接for {con, err1 := listen.Accept()if err1 != nil {fmt.Println("等待客户端连接失败, err = ", err1)return} else {// 连接成功fmt.Printf("等待连接成功,con = %v, 接收到的客户端信息:%v \n", con, con.RemoteAddr().String())}// 准备协程,协程内容不处理客户端服务请求go process(con)}
}

初识反射

在go语言中,反射(Reflection)是指程序在运行时检查变量的类型和值,并且可以修改这些变量的值、调用其方法以及获取其字段的信息的能力。反射是一种强大的元编程工具,可以让程序在运行时动态地获取和操作类型信息,而不需要在编译时确定。在go语言中,反射是通过reflect包来实现的,以下是反射具体能做的一些事:

1)反射可以在运行时动态获取变量的各种信息,比如变量的类型,类别等信息

2)如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)

3)通过反射,可以修改变量的值,可以调用关联的方法。

4)使用反射,需要import("reflect")

反射相关的使用函数可以通过如下的函数进行操作:

1)reflect.TypeOf(变量名),获取变量的类型,返回reflect.Type类型

2)reflect.ValueOf(变量名),获取变量的值,返回reflect.Value类型(reflect.Value是一个结构体类型),通过reflect.Value,可以获取到关于该变量的很多信息。

对基本类型反射

package mainimport ("fmt""reflect"
)// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {// 1.调用TypeOf()函数,返回reflect.Type类型数据reType := reflect.TypeOf(i)fmt.Println("reType: ", reType)           // reType:  intfmt.Printf("reType的具体类型是: %T \n", reType) // reType的具体类型是: *reflect.rtype// 2.调用ValueOf()函数,返回reflect.Value类型数据reValue := reflect.ValueOf(i)fmt.Println("reValue: ", reValue)        // reValue:  100fmt.Printf("reValue的具体类型是: %T", reValue) // reValue的具体类型是: reflect.Value// reValue转成空接口i2 := reValue.Interface()// 类型断言n := i2.(int)n1 := n + 30fmt.Println("n1: ", n1) // n1:  130}func main() {// 对基本数据类型进行反射var num int = 100testReflect(num)
}

这里可以通过下图深入进行了解反射:

对结构体反射

package mainimport ("fmt""reflect"
)// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {// 1.调用TypeOf()函数,返回reflect.Type类型数据reType := reflect.TypeOf(i)fmt.Println("reType: ", reType)           // reType:  intfmt.Printf("reType的具体类型是: %T \n", reType) // reType的具体类型是: *reflect.rtype// 2.调用ValueOf()函数,返回reflect.Value类型数据reValue := reflect.ValueOf(i)fmt.Println("reValue: ", reValue)           // reValue:  100fmt.Printf("reValue的具体类型是: %T \n", reValue) // reValue的具体类型是: reflect.Value// reValue转成空接口i2 := reValue.Interface()// 类型断言n, flag := i2.(Student)if flag {fmt.Printf("学生的名字是:%v, 学生的年龄是: %v", n.Name, n.Age) // 学生的名字是:张三, 学生的年龄是: 18}
}// 定义学生结构体
type Student struct {Name stringAge  int
}func main() {// 对结构体反射stu := Student{Name: "张三",Age:  18,}testReflect(stu)
}

得到的结果如下所示:

如果想获取变量的类别,可以看一下如下的示例代码:

package mainimport ("fmt""reflect"
)// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {// 1.调用TypeOf()函数,返回reflect.Type类型数据reType := reflect.TypeOf(i)// 2.调用ValueOf()函数,返回reflect.Value类型数据reValue := reflect.ValueOf(i)// 获取遍历的类别// (1)reTypek1 := reType.Kind()fmt.Println("reType:", k1) // reType: struct// (2)reValuek2 := reValue.Kind()fmt.Println("reValue:", k2) // reType: struct// 获取变量的类型// reValue转成空接口i2 := reValue.Interface()// 类型断言n, flag := i2.(Student)if flag { // 类型断言成功fmt.Printf("结构体的类型是: %T", n) // 结构体的类型是: main.Student}
}// 定义学生结构体
type Student struct {Name stringAge  int
}func main() {// 对结构体反射stu := Student{Name: "张三",Age:  18,}testReflect(stu)
}

反射修改变量的值:可以参考如下代码

package mainimport ("fmt""reflect"
)// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {reValue := reflect.ValueOf(i)// 通过SetInt方法,将i的值设置为10reValue.Elem().SetInt(10)
}func main() {// 定义一个基本数据类型var num int = 100testReflect(&num) // 传入指针地址fmt.Println(num)  // 10
}
http://www.lryc.cn/news/367241.html

相关文章:

  • nginx location正则表达式+案例解析
  • 【YOLO系列】YOLOv10论文超详细解读(翻译 +学习笔记)
  • 植物大战僵尸杂交版2024潜艇伟伟迷
  • 白话解读网络爬虫
  • 支持向量机(SVM): 从理论到实践的指南(1)
  • 万字长文|OpenAI模型规范(全文)
  • 微服务架构-正向治理与治理效果
  • normalizing flows vs 直方图规定化
  • vite打包优化常用的技巧及思路
  • k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)HPA详细解释与案例应用
  • 台式机ubuntu22.04安装nvidia驱动
  • C++ 11 【线程库】【包装器】
  • 可视化数据科学平台在信贷领域应用系列四:决策树策略挖掘
  • 数据查询深分页优化方案
  • Redis的主从复制
  • 网络安全实战基础——实战工具与攻防环境介绍
  • vue2组件封装实战系列之tag组件
  • VBA实战(Excel)(4):实用功能整理
  • nginx mirror流量镜像详细介绍以及实战示例
  • Android14 WMS-窗口添加流程(二)-Server端
  • 【传知代码】DETR[端到端目标检测](论文复现)
  • Edge浏览器十大常见问题,一次性解决!
  • lubuntu / ubuntu 配置静态ip
  • 15、matlab绘图汇总(图例、标题、坐标轴、线条格式、颜色和散点格式设置)
  • 调试环境搭建(Redis 6.X 版本)
  • postgres数据库报错无法写入文件 “base/pgsql_tmp/pgsql_tmp215574.97“: 设备上没有空间
  • 力扣2762. 不间断子数组
  • OpenCV学习(4.8) 图像金字塔
  • 【TB作品】msp430f5529单片机,dht22,温湿度传感器,OLED显示屏
  • Kotlin 异常处理