Ainx-V0.2-简单的连接封装与业务绑定

在这里插入图片描述

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。
📗本文收录于Ainx系列,大家有兴趣的可以看一看
📘相关专栏Rust初阶教程、go语言基础系列、spring教程等,大家有兴趣的可以看一看
📙Java并发编程系列,设计模式系列、go web开发框架 系列正在发展中,喜欢Java,GoLang,Rust,的朋友们可以关注一下哦!


📙 本文大部分都是借鉴刘丹冰大佬的zinx框架和文章,更推荐大家去读大佬的原文,本文只是个人学习的记录

文章目录

    • Ainx-V0.2-简单的连接封装与业务绑定
      • aiface创建iconnection.go
      • anet 创建iconnection.go
      • 重新更更正⼀一下Server.go中 处理理conn的连接业务

Ainx-V0.2-简单的连接封装与业务绑定

V0.1版本我们已经实现了了⼀一个基础的Server框架,现在我们需要对客户端链接和不不同的客户端链接所处 理理的不不同业务再做⼀一层接⼝口封装,当然我们先是把架构搭建起来。
现在在 ainterface 下创建⼀一个属于链接的接⼝⽂文件 iconnection.go ,当然他的实现⽂文件我们放在 anet 下的 connection.go 中。

aiface创建iconnection.go

ainx/ainterface/iconnection.go

package ainterfaceimport "net"type IConnection interface {// 启动连接,让当前连接开始工作Start()// 停止链接,结束当前连接状态Stop()//从当前连接获取原始的socket TCPConn GetTCPConnection() *net.TCPConn //获取当前连接IDGetConnID() uint32 //获取远程客户端地址信息 RemoteAddr() net.Addr
}// 定义⼀一个统⼀一处理理链接业务的接⼝口
type HandFunc func(*net.TCPConn, []byte, int) error

该接⼝的⼀些基础方法,代码注释已经介绍的很清楚,这里先简单说明⼀个HandFunc这个函数类型, 这个是所有conn链接在处理业务的函数接⼝,第⼀参数是socket原⽣链接,第二个参数是客户端请求的数据,第三个参数是客户端请求的数据长度。这样,如果我们想要指定⼀一个conn的处理业务,只要定义一个HandFunc类型的函数,然后和该链接绑定就可以了了。

anet 创建iconnection.go

ainx/anet/connection.go

package anetimport ("ainx/ainterface""fmt""net"
)type Connection struct {//当前链接的socket TCP套接字Conn *net.TCPConn// 当前链接的ID也可以称作SessionID,ID全局唯一ConnID uint32// 当前链接的关闭状态isClosed bool// 处理该链接方法的APIhandleAPI ainterface.HandFunc// 告知该链接已经退出/停止的channelExitBuffChan chan bool
}// 创建链接的方法
func NewConnection(conn *net.TCPConn, connID uint32, callback_api ainterface.HandFunc) *Connection {c := &Connection{Conn:         conn,ConnID:       connID,isClosed:     false,handleAPI:    callback_api,ExitBuffChan: make(chan bool, 1),}return c
}// 处理conn读数据的Goroutine
func (c *Connection) StartReader() {fmt.Println("Reader Goroutine is running")defer fmt.Println(c.RemoteAddr().String(), "conn reader exit!")defer c.Stop()for {buf := make([]byte, 512)cnt, err := c.Conn.Read(buf)// 读取数据失败,退出连接if err != nil {fmt.Println("recv buf err ", err)c.ExitBuffChan <- truecontinue}// 调用当前业务链(这里执行的是当前conn的绑定的handle方法)if err := c.handleAPI(c.Conn, buf, cnt); err != nil {fmt.Println("connID ", c.ConnID, "handle is err")c.ExitBuffChan <- truereturn}}
}// 启动连接,让当前链接工作
func (c *Connection) Start() {// 开启处理该链接读取到客户端数据之后的请求业务go c.StartReader()for {select {case <-c.ExitBuffChan:// 得到退出消息,不再阻塞return}}
}// 停止链接,结束当前链接状态M
func (c *Connection) Stop() {//1.如果当前链接关闭if c.isClosed == true {return}c.isClosed = true//TODO Connection Stop() 如果用户注册了该链接的关闭回调业务,那么在此刻应该显示调用// 关闭socket链接err := c.Conn.Close()if err != nil {return}//通知从缓冲队列读数据的业务,该链接已经关闭c.ExitBuffChan <- true//关闭该链接全部管道close(c.ExitBuffChan)
}// 从当前链接获取原始的socket TCPConn
func (c *Connection) GetTCPConnection() *net.TCPConn {return c.Conn
}// 获取当前链接ID
func (c *Connection) GetConnID() uint32 {return c.ConnID
}// 获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {return c.Conn.RemoteAddr()
}

重新更更正⼀一下Server.go中 处理理conn的连接业务

ainx/anet/server.go

package anetimport ("ainx/ainterface""errors""fmt""net""time"
)type Server struct {// 设置服务器名称Name string// 设置网络协议版本IPVersion string// 设置服务器绑定IPIP string// 设置端口号Port string
}// ============== 定义当前客户端链接的handle api ===========
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {//回显业务fmt.Println("[Conn Handle] CallBackToClient ...")if _, err := conn.Write(data[:cnt]); err != nil {fmt.Println("write back buf err", err)return errors.New("CallBackToClient error")}return nil
}// ============== 实现 ainterface.IServer 里的全部接口方法 ========
// 开启网络服务
func (s *Server) Start() {fmt.Printf("[START] Server listenner at IP: %s, Port %s, is starting\n", s.IP, s.Port)// 开启一个go去做服务端的Listener业务// todo 未来目标是提供更多协议,可以利用if或者switch对IPVersion进行判断而选择采取哪种协议,下面整个方法要重写go func() {//1 获取一个TCP的Addraddr, err := net.ResolveTCPAddr(s.IPVersion, s.IP+":"+s.Port)if err != nil {fmt.Println("resolve tcp addr err: ", err)return}// 2 监听服务器地址listener, err := net.ListenTCP(s.IPVersion, addr)if err != nil {fmt.Println("listen", s.IPVersion, "err", err)return}//	  已经成功监听fmt.Println("start Ainx server  ", s.Name, " success, now listenning...")//TODO server.go 应该有一个自动生成ID的方法var cid uint32cid = 0//3 启动server网络连接业务for {//3.1 阻塞等待客户端建立连接请求conn, err := listener.AcceptTCP()if err != nil {fmt.Println("Accept err ", err)continue}//3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接//3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的dealConn := NewConnection(conn, cid, CallBackToClient)cid++//3.4 启动当前链接的处理业务go dealConn.Start()}}()
}
func (s *Server) Stop() {fmt.Println("[STOP] Zinx server , name ", s.Name)//TODO  Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
}
func (s *Server) Serve() {s.Start()//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加//阻塞,否则主Go退出, listenner的go将会退出for {time.Sleep(10 * time.Second)}
}/*
创建一个服务器句柄
*/
func NewServer(name string) ainterface.IServer {s := &Server{Name:      name,IPVersion: "tcp4",IP:        "0.0.0.0",Port:      "8080",}return s
}

CallBackToClient 是我们给当前客户端conn对象绑定的handle⽅方法,当然⽬目前是server端强制绑定 的回显业务,我们之后会丰富框架,让这个⽤用户可以让⽤用户⾃自定义指定handle。
在 start() ⽅方法中,我们主要做了了如下的修改:

	//3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的dealConn := NewConntion(conn, cid, CallBackToClient)cid +//3.4 启动当前链接的处理业务go dealConn.Start()

实际上,⽬目前Zinx框架的对外接⼝口并未改变,所以V0.1的测试依然有效。我们依然可以启动V0.1的测试类经行测试,测试结果如下

=== RUN   TestServer
[START] Server listenner at IP: 0.0.0.0, Port 8080, is starting
Client Test ... start
start Ainx server   first  success, now listenning...
Reader Goroutine is running
[Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 

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

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

相关文章

leetcode链表相关题目

文章目录 1.移除链表元素方法1&#xff1a;方法2 2.合并两个有序链表3.链表的中间节点方法1方法2 4.反转单链表方法1方法2 5.分割链表6.链表中的倒数第k个节点方法1&#xff1a;方法2: 7.环形链表的约瑟夫问题8.链表的回文结构9.相交链表方法1方法2&#xff1a; 10.环形链表11.…

专业课145+总分410+华南理工大学811信号与系统考研经验华工电子信息与通信,真题,大纲,参考书。

大家好&#xff0c;今年考研顺利上岸华南理工大学&#xff0c;专业课811信号与系统145&#xff08;只差一点满分&#xff0c;有点遗憾&#xff0c;专业我跟着Jenny老师复习投入时间和精力和数学差不多&#xff0c;华工专业课难度中等&#xff0c;是一个总分提高很好的突破口&am…

【JavaScript 漫游】【014】正则表达式通关

文章简介 JS 语言中的 RegExp 对象提供正则表达式的功能。本篇文章旨在对该对象的相关知识点进行总结。内容包括&#xff1a; 正则表达式概述RegExp 对象的实例属性RegExp 对象的实例方法字符串与正则表达式相关的实例方法正则表达式匹配规则 概述 正则表达式的概念 正则表…

第三节课[LangChain]作业

文章目录 前言实践搭建向量知识库 前言 本次作业虽然是第三节课作业&#xff0c;但是在第四次作业之后才完成&#xff0c;所以用的是经过自我认知微调的小助手权重。 使用**诡秘之主和宿命之环小说&#xff08;仅用于学习和研究&#xff09;**以及设定集、百度百科&#xff0c…

【开源】JAVA+Vue.js实现天然气工程业务管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、使用角色3.1 施工人员3.2 管理员 四、数据库设计4.1 用户表4.2 分公司表4.3 角色表4.4 数据字典表4.5 工程项目表4.6 使用材料表4.7 使用材料领用表4.8 整体E-R图 五、系统展示六、核心代码6.1 查询工程项目6.2 工程物资…

414. Third Maximum Number(第三大的数)

题目描述 给你一个非空数组&#xff0c;返回此数组中第三大的数 。如果不存在&#xff0c;则返回数组中最大的数。 问题分析 注意要查找的数是数组中第三大的数&#xff0c;相同大小的数算一个&#xff0c;对于此问题可以采用先将数组排序然后查找第三大的数采用排序的方式最…

如何解决利用cron定时任务自动更新SSL证书后Nginx重启问题

利用cron定时任务自动更新SSL证书后&#xff0c;用浏览器访问网站&#xff0c;获取到的证书仍然是之前的。原因在于没有对Nginx进行重启。 据说certbot更新完成证书后会自动重启Nginx,但显然经我检测不是这回事儿。 所以我们需要创建一bash脚本&#xff0c;然后定时调用这个脚…

Vue核心基础5:数据监测、收集表单数据、过滤器

1 数据监测 【代码】 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>总结</title><scrip…

ChatGPT高效提问—prompt实践

ChatGPT高效提问—prompt实践 ​ 探索prompt在实际生活中的各种应用&#xff0c;旨在帮助理解和掌握如何将之前学到的prompt基础和技巧应用到具体实践中&#xff0c;从而在各个领域实现人工智能的价值。 ​ 通过生动的案例&#xff0c;发现并挖掘ChatGPT和prompt的无穷潜力。…

一个小而实用的 Python 包 pangu,实现在中文和半宽字符(字母、数字和符号)之间自动插入空格

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一个小巧的库&#xff0c;可以避免自己重新开发功能。利用 Python 包 pangu&#xff0c;可以轻松实现在 CJK&#xff08;中文、日文、韩文&#xff09;和半宽字符&#xff08;字母、数字和符号&#xf…

电路设计(15)——篮球赛24秒违例倒计时报警器的proteus仿真

1.设计要求 设计、制作一个篮球赛24秒违例倒计时报警器。要求&#xff1a; &#xff08;1&#xff09;具有倒计时功能。可完整实现从“24”秒开始依序倒计时并显示倒计时过程&#xff0c;显示时间间隔为1秒。 &#xff08;2&#xff09;具有消隐功能。当“24”秒倒计时…

nodejs切换版本

sudo n 18.17.0 sudo n然后键盘上下选择

PgSQL内核特性 - push-based pipeline 执行引擎

PgSQL内核特性 - push-based pipeline 执行引擎 数据库的SQL执行引擎负责处理和执行SQL请求。通常情况下&#xff0c;查询优化器会输出物理执行计划&#xff0c;一般由一系列的算子组成。当前&#xff0c;有两种算子流水线构建方式&#xff1a;1&#xff09;需求驱动的流水线&a…

AJAX——常用请求方法

1 请求方法 请求方法&#xff1a;对服务器资源&#xff0c;要执行的操作 2 数据提交 场景&#xff1a;当数据需要在服务器上保存 3 axios请求配置 url&#xff1a;请求的URL网址 method&#xff1a;请求的方法&#xff0c;GET可以省略&#xff08;不区分大小写&#xff09; …

防火墙安全策略及nat实验

要求一&#xff1a;生产区的设备在工作时间访问dmz区,仅可访问http服务器 要求二&#xff1a;办公区可以全天访问dmz区&#xff0c;其中10.0.2.20可以访问FTP服务器和HTTP服务器&#xff0c;10.0.2.10仅可以ping通10.0.3.10 要求三&#xff1a;办公区在访问服务器区时采用匿名认…

jsp课程教学管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程教学管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

【漏洞复现】狮子鱼CMS文件上传漏洞(wxapp.php)

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…

基于LLM的业务流程自动化

在当今竞争激烈的商业环境中&#xff0c;业务流程&#xff08;尤其是文档处理工作流程&#xff09;的自动化对于寻求提高效率和减少人工错误的公司来说变得至关重要。 传统方法往往难以跟上任务的数量和复杂性&#xff0c;而人工主导的流程速度缓慢、容易出错&#xff0c;并且可…

零基础学编程从哪里入手,编程实例分享,配件进出库管理系统软件

零基础学编程从哪里入手&#xff0c;编程实例分享&#xff0c;配件进出库管理系统软件 一、前言 对于刚学编程的人来说&#xff0c;多看看现有的软件实例对自己学开发软件是很有帮助的。 下面分享的实例以配件进出库管理系统软件为例说明。 软件文件下载可以点击最下方官网…

线性代数的本质——1 向量

向量是线性代数中最为基础的概念。 何为向量&#xff1f; 从物理上看&#xff0c; 向量就是既有大小又有方向的量&#xff0c;只要这两者一定&#xff0c;就可以在空间中随便移动。 从计算机应用的角度看&#xff0c;向量和列表很接近&#xff0c;可以用来描述某对象的几个不同…