Zinx框架学习 - 读写协程分离

news2024/11/26 7:39:23

Zinx - V0.7 读写协程分离

  • 之前connection使用StartReader对客户端的数据
  • 接下来我们就要对Zinx做⼀个⼩⼩的改变,就是与客户端进修数据交互的Gouroutine由⼀个变成两个,⼀个专⻔负责从客户端读取数据,⼀个专⻔负责向客户端写数据。这么设计有什么好处,当然是⽬的就是⾼内聚,模块的功能单⼀
  • Server依然是处理客户端的响应,主要关键的⼏个⽅法是Listen、Accept等。当建⽴与客户端的套接字后,那么就会开启两个Goroutine分别处理读数据业务和写数据业务,读写数据之间的消息通过⼀个Channel传递

 实现思路

  • connection.go

Connection定义添加channel

type Connection struct {
	//当前链接的socket TCP套接字
	Conn *net.TCPConn

	//链接的ID
	ConnID uint32

	//当前的链接状态
	isClosed bool

	//告知当前链接已经退出的/停止 channel(由Reader告知Writer退出)
	ExitChan chan bool

	//无缓冲d管道,用于读、写Goroutine之间的消息通信
	msgChan chan []byte

	//消息的管理MsgID 和对应的处理业务API关系
	MsgHandler ziface.IMsgHandle
}

初始化链接方法增加channel

//初始化链接模块的方法
func NewConnection(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {
	c := &Connection{
		Conn:       conn,
		ConnID:     connID,
		MsgHandler: msgHandler,
		isClosed:   false,
		msgChan:    make(chan []byte),
		ExitChan:   make(chan bool, 1),
	}
	return c
}

增加StartWriter方法

//写消息Goroutine, 专门发送给客户端消息的模块
func (c *Connection) StartWriter() {
	fmt.Println("[Writer Goroutine is running]")
	defer fmt.Println("[conn Writer exit!]", c.RemoteAddr().String())

	//不断的阻塞的等待channel的消息,进行写给客户端
	for {
		select {
		case data := <-c.msgChan:
			//有数据要写给客户端
			if _, err := c.Conn.Write(data); err != nil {
				fmt.Println("Send data error, ", err)
				return
			}
		case <-c.ExitChan:
			//代表Reader已经退出,此时Writer也要推出
			return
		}
	}
}

使用for循环不断阻塞地等待channel的消息,回写给客户端,其中退出一定是由Reader告知Writer退出,因为我们能够知道客户端退出的时候一定是Reader有异常

修改Start方法分离读写go程

//启动链接 让当前的链接准备开始工作
func (c *Connection) Start() {
	fmt.Println("Conn Start() ... ConnID = ", c.ConnID)
	//启动从当前链接的读数据的业务
	go c.StartReader()
	//启动从当前链接写数据的业务
	go c.StartWriter()
}

SendMsg中将数据通过channel发送给客户端

//提供一个SendMsg方法 将我们要发送给客户端的数据,先进行封包,再发送
func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("Connection closed when send msg")
	}

	//将data进行封包 MsgDataLen|MsgID|Data
	dp := NewDataPack()

	//MsgDataLen|MsgID|Data
	binaryMsg, err := dp.Pack(NewMsgPackage(msgId, data))
	if err != nil {
		fmt.Println("Pack error msg id = ", msgId)
		return errors.New("Pack error msg")
	}

	//将数据发送给客户端
	c.msgChan <- binaryMsg
	return nil
}

Stop方法添加告知Writer关闭

//停止链接 结束当前链接的工作
func (c *Connection) Stop() {
	fmt.Println("Conn Stop().. ConnID = ", c.ConnID)

	//如果当前链接已经关闭
	if c.isClosed == true {
		return
	}
	c.isClosed = true

	//关闭socket链接
	c.Conn.Close()

	//告知Writer关闭
	c.ExitChan <- true

	//回收资源
	close(c.ExitChan)
	close(c.msgChan)
}

当Reader退出时向ExitChan写入数据,只有Reader出现错误都会break,然后调用Stop方法,所以我们可以在Stop函数中将这个消息发送给Writer

整体思路

在Connection结构体中加入一个用于读写Goroutine通信的管道,在NewConnection中对管道做初始化处理,在StartReader()中做一些业务处理,读完数据后发送数据调用DoMsgHandler方法,在DoMsgHandler方法中又会调用Handle方法。当服务器端调用Handle方法时会调用SendMsg方法把消息发给客户端,以前是直接回写给客户端,现在是将消息发送给msgChan管道,此时StartWriter()就会得到管道传过来的数据,然后再将其发给客户端。当退出时StartReader检测到客户端退出,因为他会根据连接进行阻塞等待请求,客户端退出后会break跳出for循环,然后调用Stop方法,在Stop方法中关闭连接、告知Writer退出并回收资源,然后StartWriter得到消息就会退出

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

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

相关文章

Vue3 | Element Plus resetFields不生效

Vue3 | Element Plus resetFields不生效 1. 简介 先打开创建对话框没有问题&#xff0c;但只要先打开编辑对话框&#xff0c;后续在打开对话框就会有默认值&#xff0c;还无法使用resetFields()重置。 下面是用来复现问题的示例代码和示例GIF。 <script setup> import…

javascript基础二十一:说说你对BOM的理解,常见的BOM对象你了解哪些?

一、是什么 BOM (Browser Object Model)&#xff0c;浏览器对象模型&#xff0c;提供了独立于内容与浏览器窗口进行交互的对象 其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退&#xff0c;前进&#xff0c;刷新&#xff0c;浏览器的窗口发生变化&#xff0c;滚动条…

Redis入门到实战笔记-Java客户端

这里写目录标题 哪些好用的客户端Jedis连接池 Spring Data Redis依赖修改默认序列化方式修改序列化代码&#xff1a;反序列化方式 哪些好用的客户端 Jedis 依赖&#xff1a; <dependency><groupId>redis.clients</groupId><artifactId>jedis</artif…

原来!自动化测试项目--的完整测试流程是这样的……

目录 需求分析&#xff1a; 整体流程图&#xff1a; 分析流程&#xff1a; 测试设计&#xff1a; 测试分析&#xff1a; 测试设计&#xff1a; 用例设计&#xff1a; 用例执行和回归 用例执行标准 bug回归标准 补充用例 质量分析 bug定位 前端定位&#xff1a; …

Axios后端程序员快速入门简述

axios 它的底层是用了 XMLHttpRequest&#xff08;xhr&#xff09;方式发送请求和接收响应&#xff0c;xhr 相对于之前讲过的 fetch api 来说&#xff0c;功能更强大&#xff0c;但由于是比较老的 api&#xff0c;不支持 Promise&#xff0c;axios 对 xhr 进行了封装&#xff0…

qt5.15.2 配置 android

第一步 安装jdk&#xff0c;最好安装 jdk11&#xff0c;因为他是与qt5.15.2这个能匹配上的 右击电脑&#xff0c;选择属性&#xff0c;选择高级系统设置&#xff0c;选择环境变量。 点击新建&#xff0c;变量名为JAVA_HOME,变量值为java安装的路径。我的如下图 JAVA_HOME D:\P…

Lecture 4 Text Classification

目录 Classification 分类Text Classification Tasks 文本分类任务Topic Classification 主题分类Sentiment Analysis 情感分析Native-Language Identification 母语识别Natural Language Inference 自然语言推理 Building a Text Classifier 构建文本分类器Choosing a Classif…

JDK、Tomcat、Redis、MySQL集齐,教你如何搭建高效性能测试项目!

目录 前言&#xff1a; 1. JDK 的安装 2. Tomcat 的安装 3. Redis 环境搭建 4. 数据库的安装 5. WEB 项目搭建 6. 性能测试 7. 总结 前言&#xff1a; 作为一个软件工程师&#xff0c;怎能不知道如何搭建一个性能测试项目呢&#xff1f;性能测试是一个软件工程师不可或…

【Python从入门到进阶】23.urllib使用post请求百度翻译

接上篇《22、urllib库基本使用》 上一篇我们介绍了实现爬虫的必备基础——urllib库的学习。本篇我们来使用urllib实现百度翻译的效果。 一、在线翻译服务 当我们需要翻译一段文字时&#xff0c;百度翻译是一个很常用的工具。它是由百度公司开发的一款在线翻译服务&#xff0c…

k8s pv与pvc

1.前言 PV 是 Kubernetes 集群中的一种资源对象&#xff0c;它代表着一块物理存储设备&#xff0c;例如磁盘、网络存储或云存储等。PV 可以被多个 Pod 共享&#xff0c;并且可以独立于 Pod 存在。PV 可以配置不同的访问模式 (Access Modes)&#xff0c;例如 ReadWriteOnce、Re…

传输优化是非谈

曾倾向于优化异常流的做法竟然最保守&#xff0c;异常是小概率事件&#xff0c;处理它只保障可用性&#xff0c;而不是优化性能&#xff0c;恰恰需要加速大概率的正常流处理&#xff0c;数据中心传输优化投入大量精力在丢包检测和重传上的思路需重估。 为 1% 的可能性而增加的…

uniapp注册模板

注册模板 学生注册 <template><view class"content"><uni-forms ref"from" :modelValue"formData"><uni-forms-item label"学号" name"num" :rules"[{required: true,errorMessage: 学号不能为…

华为OD机试真题 Java 实现【比赛评分】【2023 B卷 100分】,附详细解题思路

一、题目描述 一个有N个选手参加比赛&#xff0c;选手编号为1~N&#xff08;3<N<100&#xff09;&#xff0c;有M&#xff08;3<M<10&#xff09;个评委对选手进行打分。打分规则为每个评委对选手打分&#xff0c;最高分10分&#xff0c;最低分1分。 请计算得分最…

OpenMMLab-AI实战营第二期——3.基于RTMPose的耳朵穴位关键点检测(Colab+MMPose)

文章目录 1. Colab和Google云端硬盘1.1 建立项目文件和jupyter文件1.2 Colab运行时选择1.3 关联Colab中的文件和Google云端硬盘的文件 2. Colab和MMPose2.1 环境配置2.2 配置文件修改 3. Colab相关知识 1. Colab和Google云端硬盘 参考&#xff1a; 利用Colab上的TPU训练Keras…

RVOS操作系统内存管理简单实现-02

RVOS操作系统内存管理简单实现-02 内存管理分类内存映射表&#xff08;Memory Map)Linker Script 链接脚本语法基于符号定义获取程序运行时内存分布 基于 Page 实现动态内存分配代码讲解调试 扩展 本系列参考: 学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春 整理而来&#x…

6-3 简单贪心(思想!不难)(看看这就这?)

贪心入门 贪心概念 贪心算法(又称贪婪算法)是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的选择。也就是说&#xff0c;不从整体最优上加以考虑&#xff0c;他所做出的是在某种意义上的局部最优解。 贪心算法不是对所有问题都能得到整体最优解&#x…

【自制C++深度学习推理框架】卷积层的设计思路

卷积层的设计思路 使用Im2Col来实现高性能卷积 在深度学习中实现高性能卷积有以下几个方法&#xff1a; 并行计算&#xff1a;在网络或硬件层面上&#xff0c;利用并行计算的优势对卷积过程进行加速&#xff0c;例如使用GPU。 转换卷积算法&#xff1a;卷积操作可由矩阵相乘…

【生成数据】随机漫步

使用python来生成随机漫步数据&#xff0c;再使用matplotlib将这些数据呈现出来。 随机漫步&#xff1a;每次行走都是完全随机的&#xff0c;没有明确的方向&#xff0c;结果是由一系列随机决策决定的。也可以这么认为&#xff0c;随机漫步就是蚂蚁在晕头转向的情况下&#xff…

DNS详解

2.4 DNS&#xff1a;因特网的目录服务 我们首先要了解域名和IP地址的区别。IP地址是互联网上计算机唯一的逻辑地址&#xff0c;通过IP地址实现不同计算机之间的相互通信&#xff0c;每台联网计算机都需要通过IP地址来互相联系和分别。 但由于IP地址是由一串容易混淆的数字串构成…

Java String ,StringBuffer 和 StringBuilder 类

文章目录 一、Java String 类二、Java StringBuffer 和 StringBuilder 类总结 一、Java String 类 字符串广泛应用 在 Java 编程中&#xff0c;在 Java 中字符串属于对象&#xff0c;Java 提供了 String 类来创建和操作字符串。 创建字符串 创建字符串最简单的方式如下: St…