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

news2024/11/28 4:50:55

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

目录

初识网络编程

初识反射


初识网络编程

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

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

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

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

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

func main() {
	// 打印
	fmt.Println("客户端启动。。。")
	// 调用Dial函数,参数需要指定tcp协议,需要指定服务器端的IP+PORT
	con, 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+PORT
	listen, 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 main

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

func main() {
	// 打印
	fmt.Println("客户端启动。。。")
	// 调用Dial函数,参数需要指定tcp协议,需要指定服务器端的IP+PORT
	con, 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 main

import (
	"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+PORT
	listen, 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 main

import (
	"fmt"
	"reflect"
)

// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {
	// 1.调用TypeOf()函数,返回reflect.Type类型数据
	reType := reflect.TypeOf(i)
	fmt.Println("reType: ", reType)           // reType:  int
	fmt.Printf("reType的具体类型是: %T \n", reType) // reType的具体类型是: *reflect.rtype
	// 2.调用ValueOf()函数,返回reflect.Value类型数据
	reValue := reflect.ValueOf(i)
	fmt.Println("reValue: ", reValue)        // reValue:  100
	fmt.Printf("reValue的具体类型是: %T", reValue) // reValue的具体类型是: reflect.Value

	// reValue转成空接口
	i2 := reValue.Interface()
	// 类型断言
	n := i2.(int)
	n1 := n + 30
	fmt.Println("n1: ", n1) // n1:  130

}

func main() {
	// 对基本数据类型进行反射
	var num int = 100
	testReflect(num)
}

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

对结构体反射

package main

import (
	"fmt"
	"reflect"
)

// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {
	// 1.调用TypeOf()函数,返回reflect.Type类型数据
	reType := reflect.TypeOf(i)
	fmt.Println("reType: ", reType)           // reType:  int
	fmt.Printf("reType的具体类型是: %T \n", reType) // reType的具体类型是: *reflect.rtype
	// 2.调用ValueOf()函数,返回reflect.Value类型数据
	reValue := reflect.ValueOf(i)
	fmt.Println("reValue: ", reValue)           // reValue:  100
	fmt.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 string
	Age  int
}

func main() {
	// 对结构体反射
	stu := Student{
		Name: "张三",
		Age:  18,
	}
	testReflect(stu)
}

得到的结果如下所示:

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

package main

import (
	"fmt"
	"reflect"
)

// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {
	// 1.调用TypeOf()函数,返回reflect.Type类型数据
	reType := reflect.TypeOf(i)
	// 2.调用ValueOf()函数,返回reflect.Value类型数据
	reValue := reflect.ValueOf(i)

	// 获取遍历的类别
	// (1)reType
	k1 := reType.Kind()
	fmt.Println("reType:", k1) // reType: struct
	// (2)reValue
	k2 := 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 string
	Age  int
}

func main() {
	// 对结构体反射
	stu := Student{
		Name: "张三",
		Age:  18,
	}
	testReflect(stu)
}

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

package main

import (
	"fmt"
	"reflect"
)

// 利用一个函数,函数的参数定义为空接口
func testReflect(i interface{}) {
	reValue := reflect.ValueOf(i)

	// 通过SetInt方法,将i的值设置为10
	reValue.Elem().SetInt(10)
}

func main() {
	// 定义一个基本数据类型
	var num int = 100

	testReflect(&num) // 传入指针地址
	fmt.Println(num)  // 10
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1816074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FFmpeg开发笔记(三十五)Windows环境给FFmpeg集成libsrt

《FFmpeg开发实战:从零基础到短视频上线》一书的“10.2 FFmpeg推流和拉流”提到直播行业存在RTSP和RTMP两种常见的流媒体协议。除此以外,还有比较两种比较新的流媒体协议,分别是SRT和RIST。 其中SRT全称为Secure Reliable Transport&#xf…

微信小程序毕业设计-驾校管理系统项目开发实战(附源码+论文)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…

WEB基础--Mybatis

了解Mybatis 什么是Mybatis 市面上最流行的技术架构:SSM 他们代表了 Spring业务层框架,SpringMvc WEB层框架以及MyBatis数据库持久层框架。 MyBatis 作为一个数据库持久层框架,是基于ORM规范(对象关系映射) 。类似我们以前的JDBC 和 JPA。…

【目标检测】基于深度学习的车牌识别管理系统(含UI界面)【python源码+Pyqt5界面 MX_002期】

系统简介: 车牌识别技术作为经典的机器视觉任务,具有广泛的应用前景。通过图像处理方法,车牌识别技术能够对车牌上的字符进行检测、定位和识别,从而实现计算机对车牌的智能化管理。在现实生活中,车牌识别系统已在小区停…

第二届京津冀现代商贸物流金融创新发展百人大会将于6月16日在廊坊举行

物流是实体经济的“筋络”,联接生产和消费、内贸和外贸,必须有效降低全社会物流成本,增强产业核心竞争力,提高经济运行效率。《京津冀协同发展规划纲要》赋予河北“三区一基地”的功能定位,建设全国现代商贸物流重要基…

vxeTable怎么导出excel文件

文章目录 一、代码示例二、调用导出事件参数详解下载引用 三、过滤某列数据导出 一、代码示例 <vxe-buttonclick"exportDataEvent"circleicon"vxe-icon-download">导出</vxe-button><vxe-tableborderroundstripeheight"auto"ref&…

融合商品计划与供应链管理:打造高效协同供应链生态

在当今竞争激烈的市场环境中&#xff0c;企业要想保持持续的竞争优势&#xff0c;除了拥有创新的产品和服务外&#xff0c;还需要具备高效协同的供应链管理能力。本文将探讨如何将商品计划与供应链管理紧密结合&#xff0c;以打造高效协同的供应链生态&#xff0c;从而提升企业…

3d模型转换器怎么用?---模大狮模型网

在当今数字化时代&#xff0c;3D技术被广泛应用于各行各业&#xff0c;从动画制作到工程设计再到游戏开发&#xff0c;都离不开3D模型。然而&#xff0c;由于不同软件之间的兼容性问题&#xff0c;我们常常需要将一个格式的3D模型转换成另一个格式。在这种情况下&#xff0c;3D…

CMA、CNAS软件检测报告如何收费?软件测评中心出具报告需多久?

众所周知&#xff0c;各行各业都需要资质认证&#xff0c;正如教师会有教师资格证&#xff0c;医师会有医师资格证&#xff0c;律师会有律师证&#xff0c;软件产品亦如此。对于软件测试报告来说CMA和CNAS资质认证就是获得行业甚至国家认可的重要依据。 CMA和CNAS软件检测报告…

ant组件库日期选择器汉化

ant组件库日期选择器默认英文 如何汉化 跟着官网走不能完全实现汉化。 这里提供一个解决方案&#xff0c;首先&#xff0c;通过pnpm下载moment包。 然后引入和注册文件&#xff1a; import zhCN from ant-design-vue/es/locale/zh_CN;import moment from moment;moment.loca…

导出 Whisper 模型到 ONNX

前言 在语音识别领域&#xff0c;Whisper 模型因其出色的性能和灵活性备受关注。为了在更多平台和环境中部署 Whisper 模型&#xff0c;导出为 ONNX 格式是一个有效的途径。ONNX&#xff08;Open Neural Network Exchange&#xff09;是一个开放格式&#xff0c;支持不同的深度…

Adobe Premiere 专业视频编辑软件资源下载安装!pr 2024最新版软件分享

Adobe Premiere&#xff0c;作为一款非线性视频编辑软件&#xff0c;它打破了传统线性编辑的限制&#xff0c;为用户提供了更加灵活和自由的创作空间。 在电影制作领域&#xff0c;Adobe Premiere的出色表现赢得了众多导演和剪辑师的青睐。其强大的编辑功能使得影片的剪辑过程更…

单细胞RNA测序(scRNA-seq) 理解Seurat对象存储信息含义和基本操作

单细胞测序技术是在单个细胞水平上&#xff0c;对基因组、转录组和表观基因组水平进行分析测序技术。bulk RNA-seq获得的是组织或器官等大量细胞中表达信号的均值&#xff0c;无法获取细胞之间的差异信息&#xff08;即丢失了细胞的异质性&#xff09;&#xff0c; 而单细胞测序…

快速上手 GreatSQL 8.0.32-25 with openEuler 24.03 LTS

5 月底&#xff0c;openEuler 24.03 LTS 发布&#xff0c;详情戳&#xff1a; 恭喜&#xff01;openEuler 24.03 LTS 版本发布&#xff1a;首个AI原生开源操作系统 在诸多亮点特性中&#xff0c;有一条值得注意&#xff1a; 集成 GreatSQL 数据库&#xff0c;适用于金融级应用场…

JAVA面试题:Redis分布式锁

Redis分布式锁 分布式锁使用的场景 集群情况下的定时任务,抢单,幂等性等场景 抢券场景 查询库存 -> 扣减库存 多个并发线程同时查询库存,出现超卖问题 添加互斥锁 所有线程执行操作之前必须尝试获取锁 保证一次只有一个线程能走查询库存->扣减库存的流程 Redis分…

模糊控制器实现对某个对象追踪输入

MATLAB是一个十分便捷的软件&#xff0c;里面提供了许多集成的组件&#xff0c;本文利用simulink实现模糊控制器实现对某个对象追踪输入。 这里的对象根据自己的需求可以修改&#xff0c;那么搭建一个闭环控制系统并不是难事儿&#xff0c;主要是对于模糊控制器参数的设置&…

记C#优化接口速度过程

前提摘要 首先这个项目是接手的前一任先写的项目&#xff0c;接手后&#xff0c;要求对项目一些速度相对较慢的接口进行优化&#xff0c;到第一个速度比较慢的接口后&#xff0c;发现单接口耗时4-8秒&#xff0c;是的&#xff0c;请求同一个接口&#xff0c;在参数不变的情况下…

【Linux】运维-Kubernetes(k8s)应用介绍及使用-了解

一、介绍 Kubernetes&#xff0c;也被称为K8s或Kube&#xff0c;是谷歌推出的业界最受欢迎的容器编排器。 K8s是一个架构良好的分布式系统的例子。它将集群中的所有机器都视为单个资源池的一部分。 K8s与其他成熟的分布式系统一样&#xff0c;有两层&#xff1a;头节点和工作节…

defer关键字

【1】defer关键字的作用&#xff1a; 在函数中&#xff0c;程序员经常需要创建资源&#xff0c;为了在函数执行完毕后&#xff0c;及时的释放资源&#xff0c;Go的设计者提供defer关键字 【2】案例展示&#xff1a; 【3】代码变动一下&#xff0c;再次看结果&#xff1a; 发…

Vue3【十九】自定义Hooks钩子 将数据和方法分组

Vue3【十九】自定义Hooks钩子 将数据和方法分组 Vue3【十九】自定义Hooks钩子 将数据和方法分组 每个分组都可以放置 各种生命周期钩子 分组和可以使用计算属性等 案例截图 目录结构 代码 person.vue <template><div class"person"><h2>Vue3自定…