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

欢迎来到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.mfbz.cn/a/691955.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[stm32]——uc/OS-III多任务程序

目录 一、获取uC/OS-III源码 二、移植源代码 (1)建立工程文件 (2)移植uC/OS-III源码 (3)添加工程组件和头文件路径 (4)添加头文件路径 三、修改代码 总结 一、获取uC/OS-III源码 …

jvm学习笔记(一) ----- JAVA 内存

JAVA 内存 一、程序计数器二、虚拟机栈三、本地方法栈四、堆五、非JAVA内存(堆外内存)1.元空间(Metaspace)2.直接内存 链接: jvm学习笔记(二) ----- 垃圾回收 链接: jvm学习笔记(三) ----- 垃圾回收器 一、程序计数器 虚拟机需要通过『程序计数器』记录指令执行到哪了。线程要…

高考填报志愿,怎么分析自己适合什么专业?

高考结束后,很多考生不知道自己的分数段适合什么学校,缺乏目标感,有些专业名称很大,听起来光鲜亮丽,但是是否适合自己,学什么课程,将来就业去向,这些都是需要细致了解的。 专业选择…

【Java】解决Java报错:StackOverflowError

文章目录 引言1. 错误详解2. 常见的出错场景2.1 无限递归2.2 递归深度过大2.3 方法调用层次过深 3. 解决方案3.1 优化递归算法3.2 尾递归优化3.3 增加调用栈大小3.4 检查递归终止条件 4. 预防措施4.1 使用迭代替代递归4.2 尾递归优化4.3 合理设计递归算法4.4 调整JVM参数4.5 定…

Python通过数据验证功能在Excel文件中创建下拉列表

Excel表格的灵活性和功能性深受各行各业人士的喜爱。在Excel表格中,下拉列表功能是提升数据录入效率与准确性的一个重要利器,能够为用户提供预设的选择项,限制输入范围,避免手动输入错误,还能够简化数据录入过程&#…

APP开发技术的变迁史

随着移动互联网的迅猛发展,APP(应用程序)已经成为人们日常生活中不可或缺的一部分。从最初的简单工具到如今的智能平台,APP开发技术在这十年间经历了翻天覆地的变化。本文将从多个维度探讨近十年来APP开发技术的变迁史&#xff0c…

数组中寻找符合条件元素的位置(np.argwhere,nonzero)

今天遇到一个问题,就是寻找符合条件的元素所在的位置,主要使用np.argwhere和nonzero函数 比如给我一个二维数组,我想知道其中元素大于15的位置 方法1 import numpy as np exnp.arange(30) enp.reshape(ex,[3,10]) print(e) print(e>15…

【C++】C++ 基于QT实现散列表学生管理系统(源码+数据+课程论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

造假高手——faker

在测试写好的代码时通常需要用到一些测试数据,大量的真实数据有时候很难获取,如果手动制造测试数据又过于繁重无聊,显得不够优雅,今天我们介绍的faker这个轮子可以完美的解决这个问题。faker是一个用于生成各种类型假数据的库&…

10. MySQL 用户

文章目录 【 1. 权限表 】1.1 user 权限表1.1.1 用户列1.1.2 权限列1.1.3 安全列1.1.4 资源控制列 1.2 db 表用户列权限列 1.3 tables_priv 表1.4 columns_priv 表1.5 procs_priv表 【 2. 用户管理 】2.1 创建用户 CREATE USER2.2 用户的登陆、退出登陆 MySQL退出 MySQL 2.3 重…

基于VS2022编译GDAL

下载GDAL源码;下载GDAL编译需要依赖的必须代码,proj,tiff,geotiff三个源码,proj需要依赖sqlite;使用cmake编译proj,tiff,geotiff;proj有版本号要求;使用cmake…

3D Gaussian Splatting for Real-Time Radiance Field Rendering

辐射场方法最近在基于多张照片或视频进行新视角合成方面取得了革命性进展。然而,实现高视觉质量仍然需要耗时且计算成本高的神经网络,而最近的快速方法不可避免地在速度和质量之间进行了权衡。对于无界和完整的场景(而不是孤立的物体&#xf…

nginx mirror流量镜像详细介绍以及实战示例

nginx mirror流量镜像详细介绍以及实战示例 1.nginx mirror作用2.nginx安装3.修改配置3.1.nginx.conf3.2.conf.d目录下添加default.conf配置文件3.3.nginx配置注意事项3.3.nginx重启 4.测试 1.nginx mirror作用 为了便于排查问题,可能希望线上的请求能够同步到测试…

【python报错】TypeError: can only concatenate str (not “int“) to str

【Python报错】TypeError: can only concatenate str (not “int”) to str 在Python编程中,字符串连接是一种基本且频繁的操作。然而,如果你尝试将整数(int)与字符串(str)直接连接,会遇到TypeE…

扩散模型条件生成——Classifier Guidance和Classifier-free Guidance原理解析

1、前言 从讲扩散模型到现在。我们很少讲过条件生成(Stable DIffusion曾提到过一点),所以本篇内容。我们就来具体讲一下条件生成。这一部分的内容我就不给原论文了,因为那些论文并不只讲了条件生成,还有一些调参什么的…

金融领域的AI解决方案

AI可赋能金融营销、资管、风控等领域,面向金融消费者、金融机构和金融监管机构,改善金融 市场信息对称性并提升金融交易的效率和安全性。目前,金融行业各机构对于安全认证和客户身份识别的需求较为迫切,身份识别和智能客服应用和落…

Linux编译器-gcc或g++的使用

一.安装gcc/g 在linux中是不会自带gcc/g的,我们需要编译程序就自己需要安装gcc/g。 很简单我们使用简单的命令安装gcc:sudo yum install -y gcc。 g安装:sudo yum install -y gcc-c。 我们知道Windows上区分文件,都是使用文件…

Facebook企业户 | Facebook公共主页经营

Facebook作为社交媒体巨头,拥有庞大的用户基数,因此,有效经营公共主页是获取持续流量、提升客户信任度和粘性、促进产品或服务销售与转化的关键。要优化Facebook主页,关注以下几点: 1、参与度是关键指标:因…

iOS18:借助 Al,Siri 将获得广泛的知识,以便触发各个应用的功能

iOS18:借助 Al,Siri 将获得广泛的知识,以触发各个应用的功能 预计Siri将成为iOS18中一系列与人工智能相关增强功能的核心。 根据彭博社记者马克古尔曼的一份新报告,可以得知关于苹果智能助手的一些具体升级的新信息。 Siri新的人工智能: …

【ARM Cache 及 MMU 系列文章 6.3 -- ARMv8/v9 Cache Tag数据读取及分析】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 Cache Tag 数据读取测试代码Cache Tag 数据读取 在处理器中,缓存是一种快速存储资源,用于减少访问主内存时的延迟。缓存通过存储主内存中经常访问的数据来实现这一点。为了有效地管…