【青训营X豆包MarsCode】第一课-Go 语言基础语法
Go 语言基础语法
走进 Go 语言基础语法
时间处理
时间相关的函数,以及时间的格式化
now := time.Now() |
数字解析
将字符串转成int:strconv.ParseInt(字符串,进制,精度位数) 或者 strconv.Atoi(字符串)(自动识别)
func main() { |
进程信息
当我们在命令行中输入 go run example/20-env/main.go a b c d 时,os.Args可以获取到输入的参数 a b c d。
fmt.Println(os.Getenv(“PATH”))打印了环境变量 PATH 的值,它通常包含了一系列目录,用于指定在执行命令时搜索可执行文件的路径。
fmt.Println(os.Setenv(“AA”, “BB”))设置了一个名为 AA 的环境变量,其值为 BB。如果设置成功,它不会返回任何错误,即返回 nil。如果设置失败,比如内存不足或者其他系统错误,它会返回一个非 nil 的错误对象。
使用 exec.Command 函数执行了一个外部命令,即使用 grep 命令在 /etc/hosts 文件中搜索包含 127.0.0.1 的行。如果命令执行成功,它会打印出搜索到的行;如果执行失败,它会抛出一个 panic。
func main() { |
JSON处理
序列化和反序列化
type userInfo struct { |
小技巧:鼠标悬浮在函数上,可以看到链接,可以跳转过去,非常的方便
Go 语言的实战案例
猜谜游戏
猜谜游戏是一个很简单的小游戏,但是我们可以将这个小游戏才往下拆分成更小的模块,这也是重要的编程思想——大事化小,小事化了
猜谜游戏可以再拆分成随机数模块、输入模块、比较模块
先是随机数模块
直接使用rand.Intn(maxNum)会是伪随机数,一般情况下需要使用每次运行的时间戳初始化种子,但是没有设置种子的实际运行下每次运行的数都不一样,搜索得知在 Go 1.20 及更高版本中,程序会默认使用一个隐式的随机数生成器,可能会导致每次运行时生成不同的随机数。这是因为默认的随机数生成器会基于时间等因素来生成随机数,也就是说,在高版本中,优化了这个问题。
maxNum := 100 |
接下来是输入模块
这里采用的是bufio包,进行输入的处理
fmt.Println("Please input your guess") |
不过明显直接使用Scan明明简洁多了,这种方法和直接Scan,毕竟两者的复杂性差太多了
后面有解释道这个包以后会用到,所以就采用相对曲折的方式,想想也是,曲折说明比较底层,相对来说可以自定义的空间就大,可适用场景就多
比较模块什么说的
在线词典
在线词典拆解一下,就是调用API、JSON格式化、提取信息
调用第三方API
输入:单词 ——-> 输出:音标词义
需要了解request和response的结构
HTTP请求的结构:请求行、请求头、请求体
JSON的部分属于请求体的模块
在页面中输入单词进行翻译,在开发者工具中就可以看到新的request,找到它(注意是POST)
{ |
再看response,可以看到JSON结构,直接在开发者工具中Copy-Copy as cURL(cmd),将复制下来的东西粘贴到终端中运行就可以得到网站的返回JSON
之后找一个代码自动生成的网站,将之前复制下来的东西直接丢进去,它就会自动生成响应的代码,粘贴到编译器里,就可以访问网站返回json数据
JSON格式化
request和response在收发过程中需要JSON序列化和反序列化
序列化是将一个数据结构(如结构体、对象、数组等)转换为字符串(通常是 JSON 格式)的过程。这使得数据能够以文本形式进行存储或传输。
JSON格式化没有想象中那么复杂
那么对应的API文档一个是怎么样的?
API 文档示例
关于API,这里想要展开一下
- 概述
该 API 提供了一个词典查询服务,可以将英文单词翻译成中文并返回相关信息。
- 基本信息
- API Endpoint:
POST https://api.interpreter.caiyunai.com/v1/dict
- 请求格式: JSON
- 响应格式: JSON
- 请求参数
请求体需要为 JSON 格式,包含以下字段:
字段 | 类型 | 必填 | 描述 |
---|---|---|---|
trans_type | string | 是 | 翻译类型,固定值为 "en2zh" |
source | string | 是 | 待翻译的英文单词 |
user_id | string | 是 | 用户 ID,用于标识请求用户 |
示例请求体:
{ |
- 请求头
需要设置以下请求头:
请求头 | 类型 | 描述 |
---|---|---|
Content-Type | string | 请求体类型,固定为 application/json;charset=UTF-8 |
User-Agent | string | 客户端信息 |
X-Authorization | string | 访问令牌 |
Accept | string | 接受的响应格式,通常为 application/json |
- 响应参数
响应体为 JSON 格式,包含以下字段:
字段 | 类型 | 描述 |
---|---|---|
rc | int | 响应状态码,0表示成功 |
wiki | object | 相关的维基信息,包括翻译描述和图片链接 |
dictionary | object | 包含单词发音、解释、同义词、反义词等信息 |
提取信息
对于接收到的数据,我们需要从中提取出我们想要的数据,在这里就是单词的音标和释义
首先,我们定义一个与 JSON 数据结构匹配的 Go 结构体,该结构体的字段应该与 JSON 中的键相对应,并且要使用 JSON 标签来指定映射关系。
可以直接访问结构体的字段来提取所需的信息
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs) |
到这里我们已经实现了调用第三方API实现翻译的功能
即输入单词,输出单词音标和释义
go run 文件路径 beautiful |
代理服务器
—SOCKS5
SOCKS5原理:协商、认证、请求、relay 四个阶段
协商:浏览器向代理说明自己支持的认证方式,然后代理从中选择一个自己支持的返回给浏览器
认证:(跳过)因为此处实现不加密的代理
请求:浏览器向代理发送collection请求,命令代理和某个IP端口建立连接
relay:浏览器正常发送请求,代理转发请求给真正服务器,服务器返回响应,代理也转发响应给浏览器,在转发过程中代理不注意流量的细节
TCP echo server
先做一个简单的 TCP echo server
客户端向服务器发送什么,服务器都会返回一样的数据
显示监听自己的本机端口,看看有没有客户端访问,如果有就存储在client里,给每个访问的客户端都分配一个单独的进程(或者不叫进程),总之这里应该涉及并发,也是能够体现Go语言特性和优势的地方,这里是一个典型的S/C模式
讲到这里会启动一个go-routine
server, err := net.Listen("tcp", "127.0.0.1:1080") |
那么goroutine是什么?
简单来说,goroutine是Go特色一种智能管理的、方便简洁的协程,也是Go天然支持高并发的主要条件
接下来就是逐步实现SOCKS5的四个阶段 协商、认证、请求、relay
协商+认证阶段
认证方法 authenticate(用户,程序)验证身份
func auth(reader *bufio.Reader, conn net.Conn) (err error) |
简单来说,就是客户端向服务器发出请求,某协议,支持的认证方式,然后服务器从中选择支持的认证方式
请求阶段
浏览器发送报文:版本、请求类型、ATYP目标地址类型、地址、目标端口
ATYP 的使用允许代理服务器灵活地处理不同类型的地址,因此在实现 SOCKS 代理或其他网络协议时,理解 ATYP 的含义非常重要。
relay阶段
代理服务器也已经跑通了,但是代理服务器的输出中的有个addr的输出有点在意,按理来说addr应该是目标地址,但是我换终端执行addr居然也会变,这简直就像是addr是终端的地址一样,但是这不太对。
于是我打算进行调试,既然要调试,那么就把项目代码拷贝到本地,我认为这是必要的一步
最后在调试中发现代理接收到的ATYP(目标服务器地址类型)是IPv4,而不是域名,但是我发送的命令是
curl --socks5 127.0.0.1:1080 -v http://qq.com |
也就是说客户端在curl中就把域名解析成IP地址了,应该是使用的本地DNS服务器
而为什么IP地址会不断变化呢,而且是随着终端的终端的变化而变化,为了验证以上前提,先进行一步检验
本地的不同终端似乎没有出现这种现象,只有云端的会出现
Q、不同终端访问qq.com网址使用的IP会不同吗?
A:是的,不同终端访问同一个网址(如 qq.com)时,使用的 IP 地址可能会不同。这主要受到以下几个因素的影响:
- DNS 解析:当你访问一个网址时,首先会通过 DNS(域名系统)将域名解析为 IP 地址。不同的 DNS 服务器可能返回不同的 IP 地址,尤其是对于大型网站,它们可能有多个服务器并采用负载均衡技术。
- 地理位置:某些网站可能会根据用户的地理位置返回不同的 IP 地址,以便提供更快的访问速度或更好的内容分发。例如,访问 qq.com 的用户如果在中国大陆,可能会解析到与在海外用户不同的 IP 地址。
- 网络环境:不同的网络环境(如家庭 Wi-Fi、移动网络等)可能使用不同的出口 IP 地址。在同一个网络下,不同的设备通常会共享同一个公网 IP 地址,但如果网络使用了 NAT(网络地址转换),内部设备的访问可能被不同的网络策略影响。
- 动态 IP 地址:某些 Internet 服务提供商(ISP)使用动态 IP 地址分配,因此同一用户在不同时间连接互联网时,可能会获得不同的 IP 地址。
探究到这里告一段落,先把课程看完
课程的最后,正如前面所说,讲了如何配置proxy,就只需要安装一个 Proxy SwichyOmega 即可,在 Proxy SwichyOmega 中配置代理服务器的地址,也就是说讲浏览器连接到代理服务器,由代理服务器全权负责我们 访问目标服务器的动作
到这里感觉,代理,就是一台主机请另一台主机帮忙访问,相当于请同学用他自己的电脑帮我访问我想要访问的网站,他访问之后得到的数据给我,就这样而已,由于是他访问,所以那端的服务器当然看到访问的IP地址是同学的IP地址,不会知道我的存在,就是一个这么简单的过程