golang网络编程day6(结)

golang网络编程day6

  • golang websocket编程
  • golang rpc编程
  • 最终总结

golang websocket编程

什么是websocket?,和socket是一回事吗?
websocket和传统的socket有些相似,又有些重要区别
1.WebSocket:
(1)websocket提供了在单个TCP连接上进行全双工通信的能力,特别用于浏览器和服务器之间的交互。(2)它是一种在单个长期连接上提供实时双向数据传输的网络协议。(3)websocket通常用于网页应用中,允许服务器主动向客户端发送数据,非常适合需要频繁和实时交互的应用场景。

2.socket:
(1)通常指的是网络编程中的一个概念,指的是提供两个结点之间数据交换的端点。(2)sockets可以用于不同类型的网络(包括TCP/UDP),支持多种通信协议。(3)它们是进行网络通信的基础,被用于构建包括webSocket在内的多种网络应用。

总结websocket是建立在socket基础上的一种特定协议,专为网络应用提供实时双向通信。

下面来看一个golang websocket服务端示例:

package mainimport ("fmt""log""net/http""time""github.com/gorilla/websocket"
)var (upgrader = websocket.Upgrader{ReadBufferSize:  1024,WriteBufferSize: 1024,}
)func main() {http.HandleFunc("/ws", handleWebSocket)err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal("ListenAndServe: ", err)}
}func handleWebSocket(w http.ResponseWriter, r *http.Request) {// 将HTTP连接升级为WebSocket连接conn, err := upgrader.Upgrade(w, r, nil)if err != nil {log.Println("upgrade error: ", err)return}defer conn.Close()for {// 从WebSocket连接中读取消息_, message, err := conn.ReadMessage()if err != nil {log.Println("read error: ", err)break}// 打印接收到的消息log.Printf("recv: %s\n", message)// 将当前时间作为响应消息发送给客户端resp := []byte(time.Now().String())err = conn.WriteMessage(websocket.TextMessage, resp)if err != nil {log.Println("write error: ", err)break}}
}

要搞懂这个代码先了解里面用到的函数
WebSocket Upgrader:是Gorilla Websocket包中的一个结构体,用于将HTTP请求升级到WebSocket连接。这是实现WebSocket通信的关键步骤。
详细解读字段和方法:
ReadBufferSizeWriteBufferSize:这些字段设置了 WebSocket 连接的读写缓冲区大小。缓冲区大小影响数据传输的性能。
Upgrade 方法,Upgrader结构体的Upgrade方法负责执行从HTTP到WebSocket的升级过程。这个方法接收响应写入器,HTTP请求指针,以及一个可选响应头(http.Header)作为参数,并返回一个websocket连接,这个连接是*websocket.Conn类型的。如果升级失败则返回错误。

*websocket.Conn类型:是WebSocket连接的核心类型
得到了这个连接,就可以进行数组操作了,这个和TCP那个Conn的用法很像。这里之间来看这个连接的方法和字段。
具体属性:
1.RemoteAddr和LocalAddr
2.Subprotocol:返回协商的webSocket子协议
3.underlyingConn:返回底层的网络连接
方法:
ReadMessage:用于从WebSocket连接中读取数据,没有参数,返回值有三个,消息类型(文本或二进制消息),消息内容(字节切片),和error。
WriteMessage:用于向WebSocket连接中写入一个消息,参数:消息类型(文本或二进制,传参这么传websocket.TextMessage或websocket.BinaryMessage)和要发送的消息内容(字节切片)。返回值只有个error。

使用场景:在处理HTTP请求的函数中使用Upgrader可以轻松的将HTTP连接转换为WebSocket连接,从而允许双向通信。
总之:Upgrader提供了WebSocket协议所需的协议切换机制,使得你可以在web应用程序中实现实时,双向的通信功能。

了解完这些这个代码那看懂肯定轻轻松松。

我这里来总结以下代码的流程
上了看到了一个var 定义了upgrader结构体,设置了websocket连接的读写缓冲区大小。

main函数:
注册函数,一旦请求/ws,就会由handlewebsocket函数来进行处理。然后打开服务器接一下错误就完事了。

注册函数:
先调用upgrader的upgrade方法,将HTTP升级成websocket,拿到websocket.Conn就可以进行数据操作了。这个连接也是要记得关。

有个无限循环,因为注册函数是服务器端的,直接等待客户端发信息,所以readmessage一直在等请求信息。接到信息后进行数据发送给客户端。然后基本结束。

思考:从代码上看,显然websocket编程是需要建立连接的。websocket是一种在单个TCP连接上提供全双工通信信道的协议,在通信双方(客户端和服务器)首先通过HTTP协议握手,然后这个连接会被升级到Websocket连接。这个过程中conn代表的就是这个持久化的WebSocket连接,它允许双发在连续持续打开的情况下互相发送数据和接受数据。

引发的一个疑问:

HTTP 协议本身是无状态的,通常被认为是不持久化连接的。它基于请求-响应模式,意味着每次通信都是独立的:客户端向服务器发送一个请求,服务器处理请求并返回响应,然后连接关闭。这种模式通常称为“无连接”或“短连接”。

我对连接这个点有疑问
回答:这里我混淆了无连接的性质,当时没有理解好。
HTTP协议本身是无状态的,通常是基于请求-响应模式,但是每次请求通常会打开一个新的TCP连接,然后才关闭,这个才是无连接的真正理解。
在webSocket的握手过程,websocket握手基于一个标注的HTTP请求,这个请求包含了特定的头部信息,表明客户端希望将连接升级到websocket,如果服务器支持websoket,它会发送一个特殊的HTTP响应,同意这个升级。一旦握手完成,同一TCP连接就被升级为WebSocket连接。从那时起,这个连接就转换为持久的全双工通信通道,不再是原先的无连接HTTP模式。
因此:HTTP协议虽然本身无连接,但是Websocket利用HTTP的初始握手建立的持久化连接。


golang rpc编程

ps:golang会专门学grpc,这里只是一个有关rpc的简单了解学习。

RPC是什么?
RPC(远程过程调用)是一种允许程序调用另一台计算机上的程序或服务的奇数,就好像这些程序或服务在本地一样。RPC抽象了网络通信的复杂性,使开发者能够像调用本地函数一样调用远程函数。它通常涉及客户端-服务器架构,客户端发送请求到服务器斌等待响应。

RPC实现通常负责序列化(将对象转换为可传输的格式)和反序列化(将传输的数据转换回对象)以及网络通信。RPC提供了一种透明的方式来进行跨网络的服务调用,使得分布式系统的开发和维护更加简单高效

golang提供了标准库中的net/rpc包来实现远程过程调用RPC编程。通过RPC,我们可以让客户端之间调用服务端的函数就像调用本地的函数一样。

下面是一个简单的golang RPC示例,包含服务端和客户端两部分。
服务端:

package mainimport ("errors""log""net""net/rpc"
)type Args struct {A, B int
}type Arith struct{}func (t *Arith) Multiply(args *Args, reply *int) error {*reply = args.A * args.Breturn nil
}func (t *Arith) Divide(args *Args, reply *float64) error {if args.B == 0 {return errors.New("divide by zero")}*reply = float64(args.A) / float64(args.B)return nil
}func main() {arith := new(Arith)rpc.Register(arith)l, err := net.Listen("tcp", ":1234")if err != nil {log.Fatal("listen error: ", err)}log.Println("rpc server listening on :1234 ...")rpc.Accept(l)
}

先把每部分啥是啥看懂:
1.定义数据结构和服务
Args 结构体定义了 RPC 方法的参数,包含两个整数 A 和 B
Arith 类型定义了 RPC 服务,可以看到它有两个方法:Multiply 和 Divide
2.实现RPC方法:
Multiply 方法接收 Args 类型的参数和一个整数指针作为回复。它将 A 和 B 相乘的结果赋给回复。
Divide 方法也接收 Args 类型的参数和一个浮点数指针作为回复。它执行除法操作,并处理除以零的错误情况。
3.启动 RPC 服务
使用 new(Arith) 创建一个 Arith 实例,并通过 rpc.Register 注册为 RPC 服务。
通过 net.Listen 在 TCP 协议的 1234 端口上监听传入的连接。
使用 rpc.Accept 接收连接并为每个连接提供服务。

rpc.Register()是net/rpc包中的函数,用于注册一个RPC服务。这个函数的主要目的是将给定的对象的方法注册为远程过程调用的服务。
当调用这个函数时,它会检查提供的对象的公开方法,并将它们注册为可通过网络远程调用的方法。这些方法必须满足特定的签名要求,比如必须有两个参数,第二个参数是指针类型,并且有一个error类型的返回值。
通过这种方式,rpc.Register使得对象的方法可以从远程客户端通过RPC调用,从而实现跨网络的函数调用。这对构建分布式系统和服务至关重要。

rpc.Accept()是net/rpc包中的函数,这个函数用于接收指定监听器上的连接的请求,并为每个连接请求提供RPC服务。当服务器调用rpc.Accept时,它会阻塞并等待新的连接。一旦有新的连接,服务器会处理该连接上的RPC调用。这个函数是启动RPC服务并响应远程调用的关键步骤。通过调用这个函数,服务器能够不断接收并处理来自客户端的远程调用请求。这使得服务器能够长时间允许,持续的响应客户端请求。

服务端代码总结:
该服务端定义了一个Arith结构体,其中包含Multiply和Divide两个方法。Multiply方法实现了两个整数相乘的功能,Divide方法实现了两个整数相除的功能。当除数为0时,Divide方法将返回一个错误。
服务端在启动时,首先使用 rpc.Register函数注册了Arith类型,并监听端口号为1234的TCP连接,当有客户端连接时,服务端会收到请求并进行处理

客户端代码

epackage mainimport ("fmt""log""net/rpc"
)type Args struct {A, B int
}func main() {client, err := rpc.Dial("tcp", "localhost:1234")if err != nil {log.Fatal("dialing error: ", err)}args := Args{4, 5}var reply int// 调用Multiply方法err = client.Call("Arith.Multiply", &args, &reply)if err != nil {log.Fatal("arith error: ", err)}fmt.Printf("Multiply: %d * %d = %d\n", args.A, args.B, reply)args = Args{10, 0}var fReply float64// 调用Divide方法err = client.Call("Arith.Divide", &args, &fReply)if err != nil {log.Fatal("arith error: ", err)}fmt.Printf("Divide: %d / %d = %f\n", args.A, args.B, fReply)
}

先看懂代码由哪几部分组成
也定义了一个Args结构体,参数和服务端一样。

1.建立连接:使用rpc.Dial连接到RPC服务器(这个例子中,指定连接的是地址为localhost:1234,会返回一个RPC客户端实例和可能的错误。
2.准备参数和接收回复的变量:定义了Args结构体,并创建了一个变量args用于存放方法参数和一个变量reply用于接收方法的返回值。
3.调用远程方法:使用client.Call调用远程服务器上的方法。方法的名称(如Arith.Multiply),参数(&args)和回复指针(&reply)作为参数传递给Call方法.
4.处理错误和输出结果:检查Call方法返回的错误,并输出RPC调用的结果。

可能看着有点不懂,这里对里面用到的函数进一步解读

client, err := rpc.Dial(“tcp”, “localhost:1234”)
是go语言net/rpc包中的函数,用于创建一个到RPC服务器的客户端连接,参数:1,网络协议,2,服务器的地址和端口。
返回值:*rpc.Client对象,用于后续的RPC调用,使用这个客户端对象,你可以调用服务器上注册的远程过程,就像在本地调用普通函数一样。

*rpc.Client对象解读:
这个类型代表一个RPC客户端实例。这个客户端实例用于RPC服务器进行通信。
1.它有Client.Call方法,你可以发起一个同步的远程过程调用。这意味着Call方法会阻塞,直到远程调用返回结果或发生错误。Client.Call()接收三个参数,serviceMethod字符串,格式为"Service.Method",这制定了要调用的远程服务及其方法。args参数,这是要传递给远程方法的参数。reply参数,这是一个指向回复值得指针,远程方法调用得结果将被写入到这个位置。返回值:该方法返回一个error类型得值。Client.Call方法通常用于需要等待结果才能继续指向得场景,例如当客户端需要处理服务器返回得数据后者需要根据服务器响应来做出决策时。
2.还提供了Go方法,用于异步调用远程方法。这种方式不会阻塞调用者,允许你在等待远程调用结果的同时执行其他操作。
3.连接管理,客户端维护于RPC服务器的网络连接,负责数据的发送和接收。
总之该对象时实现客户端和服务器之间通信的核心,它抽象了底层的网络操作,使得开发者可以像调用本地方法一样调用远程方法。

继续看上面代码,通过代码来看这个Call函数怎么用的:

args := Args{4, 5}var reply int// 调用Multiply方法err = client.Call("Arith.Multiply", &args, &reply)if err != nil {log.Fatal("arith error: ", err)}fmt.Printf("Multiply: %d * %d = %d\n", args.A, args.B, reply)

err = client.Call(“Arith.Multiply”, &args, &reply)先单独分析这一句,来看看这个call函数到底怎么用的。
”Arith.Multiply" 是要调用的远程函数。它由两部分组成:服务名(Arith)和
方法名
(Multiply),这个服务我在服务端注册了。
&args 是传递给远程函数 Multiply 的参数,args 是 Args 类型的变量包含了该方法所需的所有输入参数
&reply 是一个指向回复值的指针,远程方法执行后的结果将写入到这个变量中
返回值只有一个错误。注意这个调用过程是阻塞的,程序会在这一行代码等待,直到远程调用完成并返回结果。

限制看懂这个段代码应该不难了,创建了Args结构体然后进行了实例化,然后定义了reply,这个是拿来接结果的。然后就可以通过call方法调用服务端上的Arith服务的Multiply函数了。下面那段代码如法炮制 。一样的流程。这样就实现了调用服务端上的函数了。

客户端代码流程总结:
客户端通过rpc.Dial函数连接到服务端,这个函数会返回client对象,这个对象就是操作的关键,然后通过client.Call函数调用服务端的方法,客户端首先调用了Multiply方法,传入参数4,5,并接收服务段返回的结果,然后调用Divide方法,传入参数10和0,由于除数为0,服务端将返回一个错误。

有一点需要注意Golang的RPC编程中,客户端,服务端的方法名、参数和返回值类型必须一致,否则会出现调用失败。


golang网络编程学习总结:

刚刚接触网络编程时,我是啥也看不懂,空有计算机网络的知识,这些函数我都不知道有什么用,但是经过理解例子,不断地对这些函数进行学习,和代码地逻辑流程,现在回头再看第一天地实践例子,已经感觉是非常轻松了。这也让我感觉到写博客一方面帮我记忆,写的过程中也记下了思考。

下一个板块就是gin框架和grpc的学习了。

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

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

相关文章

【C语言】socket编程接收问题

一、recv()函数接收到的返回值为0表示对端已经关闭 在TCP套接字编程中,通过recv()函数接收到的返回值为0通常表示对端已经关闭了套接字的发送部分。这是因为TCP是一个基于连接的协议,其中有定义明确的连接建立和终止流程;当对端调用close()或…

Vue2.0 组件传值方式:父传子、子传父、非父子组件传值

文章目录 1. 父组件向子组件进行传值父组件:子组件: 2. 子组件向父组件传值子组件:父组件: 3. 非父子组件进行传值公共bus.js组件A:组件B: 每次总结都是在加强一遍记忆 1. 父组件向子组件进行传值 父组件&…

数据分析:当当网书籍数据可视化分析

当当网书籍数据可视化分析 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏📁评论&…

GA/T 1707-2019 防爆安全门检测

防爆安全门是指能抵抗爆炸冲击波作用的特种防护门,根据防爆门的防爆性能的不同,分为非接触爆炸防爆门和防接触爆炸防爆门,根据防爆能力的不同,分为不同等级。 GA/T 1707-2019 防爆安全门检测项目 测试项目 测试标准 外观质量 …

基于场景文字知识挖掘的细粒度图像识别算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读:基于场景文字知识挖掘的细粒度图像识别算法1、研究背景2、方法提出方法模块 3、试验4、文章贡献 二、RNN代码学习2.1、什么是RNN2…

Day43 377组合总和IV 70爬楼梯 322零钱兑换 279完全平方数 139单词拆分

377 组合总和IV 给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。 示例: nums [1, 2, 3]target 4 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序…

快速上手Vue开发:npm命令大全

文章目录 一、简介二、基础命令1、设置镜像2、安装包3、卸载包4、更新包5、查看已安装包6、检查过时的包7、查看帮助8、显示 npm 根目录9、创建 package.json 文件10、清除缓存 一、简介 npm是JavaScript运行时环境Node.js的默认包管理器,全称是Node Package Manage…

Mysql学习记录补充

索引 在无索引情况下,就需要从第一行开始扫描,一直扫描到最后一行,我们称之为 全表扫描,性能很低。 如果我们针对于这张表建立了索引,假设索引结构就是二叉树,那么也就意味着,会对age这个字段…

关于python中的import

导入指定路径下的模块 sys模块中的sys.path中保存在代码运行时依次寻找模块的路径,sys.path的返回值是一个列表,可以通过向列表中插入或追加路径,来实现调用指定路径下模块的查找。 除了在运行时添加环境变量还可在修改配置文件来添加环境变…

Linux|Grep 命令的 12 个实用示例

您是否曾经遇到过在文件中查找特定字符串或模式的任务,但不知道从哪里开始查找?那么,grep 命令可以拯救你! grep 是一个功能强大的文件模式搜索器,每个 Linux 发行版都配备了它。如果出于某种原因,它没有安…

【C++入门学习指南】:函数重载提升代码清晰度与灵活性

🎥 屿小夏 : 个人主页 🔥个人专栏 : C入门到进阶 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一、函数重载1.1 函数重载的概念1.2 函数重载的作用1.3 C支持函数重载的原理1.4 扩展 &…

C++ STL库详解:容器适配器stack和queue的结构及功能

一、stack 1.1stack的介绍 1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器&#xf…

图数据库(neo4j)在工业控制中的应用

图模型 事物的模型中,除了它自身的某些特征之外,还包括它与其它事物的关系特征,例如一个学生的属性包括姓名,性别,年龄等属性,同时,他还有许多关系属性,比如他属于哪一个院系&#x…

背篼酥电子编程内部集中培训寒假营

寒假营专栏 7节理论加3节比赛 第一课 背篼酥电子编程内部集中培训第一课-基础知识 第二课 背篼酥电子编程内部集中培训第二课–软件环境 第三课 背篼酥电子编程内部集中培训第三课–蜂鸣器 第四课 背篼酥电子编程内部集中培训第四课–红外避障 第五课 背篼酥电子编程…

修改照片尺寸好用的工具,分享4款!

在数字时代,照片已成为我们生活的一部分,而如何调整照片尺寸以满足不同的需求,则显得至关重要。今天,我们就来探讨那些可以修改照片尺寸的工具,让你轻松应对各种尺寸需求。 茄子水印相机 这是一款功能强大、操作简单的…

MacBook有必要装清理软件吗?CleanMyMac X v4.14.6 直装特别版 附安装教程

MacBook是苹果公司的一款高端笔记本电脑,但是,随着使用时间的增长,MacBook也会出现一些问题,比如运行缓慢、卡顿、垃圾文件堆积、磁盘空间不足等。这些问题不仅影响了用户的使用体验,也可能对MacBook的寿命和安全性造成…

已经购买了阿里云服务器ECS,如何在上面部署幻兽帕鲁服务器?(一键安装非常简单)

很多人都知道阿里云可以支持一键购买并部署幻兽帕鲁服务器,不需要你进行任何配置,也不用你登录服务器,通过查看和管理计算巢面板就可以了,直接就可以开玩了。但是如果你已经有了一台阿里云服务器ECS那么该怎么去搭建幻兽帕鲁服务器…

Centos 内存和硬盘占用情况以及top作用

目录 只查看内存使用情况: 内存使用排序取前5个: 硬盘占用情况 定位占用空间最大目录 top查看cpu及内存使用信息 前言-与正文无关 生活远不止眼前的苦劳与奔波,它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

c++类继承

一、继承的规则 (1)基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为protected时,那么基类成员在派生类中的访问权限最高也为protected,高于protected会降级为protected,但低…

通讯基本概念

通信的方式有多种,按数据传输方式可分为串行通讯和并行通信;按通信数据同步方式可分为同步通信和异步通信;按数据通信的方向可分为 一、串行通信和并行通信 串行通信:设备之间通过少量的数据信号线(一般是8根以下&am…