基于zinx的go tcp通信案例

2023-10-27

基于zinx的go tcp通信示例

一、zinx简介:(https://gitee.com/Aceld/zinx/)

Zinx是一个基于Golang的轻量级tcp服务框架,根据官方的定位,zinx是在游戏领域或者其他长链接的领域的轻量级企业框架,其使用简单,性能高效,能够很方便的帮助用户搭建tcp通信服务。

一个简单的zinx-tcp服务搭建只需要三步:

  1. 创建server服务实例
  2. 配置自定义路由及业务
  3. 启动服务
package main

import "github.com/aceld/zinx/znet"

func main() {
	//1 创建一个server服务
	s := znet.NewServer()

	//2 配置路由
	s.AddRouter(1, &PingRouter{})

	//3 启动服务
	s.Serve()
}

框架的基本架构:

在这里插入图片描述

特点:

  • 路由定义
  • 消息封装
  • 支持多路由
  • 链接管理
  • 消息队列和多任务机制

二、zinx基本封装实现tcpserver,clent工具包

  1. tcp-server服务端封装

    1. 配置注入

      //zinx的配置文件的格式详见github.com/aceld/zinx/zconf,要使用server服务,需要完成配置的初始化,我们创建一个server结构体,基于zinx进行服务端封装,并接收使用者进行配置注入,如:
      type TcpServer struct {
      	server ziface.IServer
      	lock   sync.RWMutex
      }
      
      var instance *TcpServer
      
      func NewServer(config *zconf.Config) *TcpServer {
      	// 创建 Zinx 服务器
      	if instance == nil {
      		server := znet.NewUserConfServer(config)
      
      		server.SetOnConnStart(ConnStart)
      		server.SetOnConnStop(ConnLost)
      		instance = &TcpServer{server: server}
      	}
      	return instance
      }
      
      
    2. 服务实例化

      func NewServer(config *zconf.Config) *TcpServer {
      	// 创建 Zinx 服务器
      	if instance == nil {
      		server := znet.NewUserConfServer(config)
      
      		server.SetOnConnStart(ConnStart)
      		server.SetOnConnStop(ConnLost)
      		instance = &TcpServer{server: server}
      	}
      	return instance
      }
      
    3. 路由注册(消息收发)

      // 路由注册入口
      func (ts *TcpServer) RegisterRouter(uid uint32, router ziface.IRouter) {
      	if ts.server == nil {
      		return
      	}
      	//ts.restartServer()
      	ts.server.AddRouter(uid, router)
      }
      
      // 创建一个可收发信息的路由,便于测试
      type RDuplex struct {
      	znet.BaseRouter
      }
      
      func (rd *RDuplex) Handle(request ziface.IRequest) {
      	fmt.Printf("receive from client msgID=%d, data=%s\n", request.GetMsgID(), string(request.GetData()))
      	err := request.GetConnection().SendMsg(2, []byte("hello zix hello Router"))
      	if err != nil {
      		fmt.Println(err)
      	}
      }
      
      
    4. 服务启动/停止

      
      func (ts *TcpServer) Start(ctx context.Context) error {
      	ts.server.Serve()
      
      	select {}
      }
      
      func (ts *TcpServer) Stop(ctx context.Context) error {
      	ts.server.Stop()
      	return nil
      }
      
  2. tcp-client服务端封装

    1. 配置注入

      type (
      	TcpClient struct {
      		lock sync.RWMutex
      		conn net.Conn
      		dp   ziface.IDataPack
      
      		option   Option
      		revChan  chan int
      		stopChan chan int
      	}
      // 	服务配置
      	Option struct {
      		ServerAddr string
      		Retry      int
      	}
      )
      
      var instance *TcpClient
      
      func NewClient(opt Option) *TcpClient {
      	if instance == nil {
      		instance = &TcpClient{
      			option:  opt,
      			revChan: make(chan int, 1),
      			dp:      zpack.Factory().NewPack(ziface.ZinxDataPack),
      		}
      		instance.initTcpClient()
      	}
      	fmt.Println("tcp client start.")
      	return instance
      }
      
    2. 服务实例化

      func NewClient(opt Option) *TcpClient {
      	if instance == nil {
      		instance = &TcpClient{
      			option:  opt,
      			revChan: make(chan int, 1),
      			dp:      zpack.Factory().NewPack(ziface.ZinxDataPack),
      		}
      	}
      	fmt.Println("tcp client start.")
      	return instance
      }
      
    3. 服务监听

      func (cli *TcpClient) waitRecv() {
      	for {
      		select {
      		case <-cli.revChan:
      			go cli.recv()
      		}
      	}
      }
      
    4. 消息收发

      func (cli *TcpClient) Send(data []byte) {
      	msg, _ := cli.dp.Pack(zpack.NewMsgPackage(uint32(1002), data))
      	_, err := cli.conn.Write(msg)
      	if err != nil {
      		fmt.Println(err.Error())
      		return
      	}
      	cli.revChan <- -1
      }
      
      func (cli *TcpClient) recv() {
      	headData := make([]byte, cli.dp.GetHeadLen())
      	_, err := io.ReadFull(cli.conn, headData)
      	if err != nil {
      		fmt.Println(err.Error())
      	}
      
      	msgHead, err := cli.dp.Unpack(headData)
      	if err != nil {
      		fmt.Println(err.Error())
      	}
      
      	//if msgHead.GetDataLen() == 0 {
      	//	fmt.Println(err.Error())
      	//}
      	msg := msgHead.(*zpack.Message)
      	msg.Data = make([]byte, msg.GetDataLen())
      	_, err = io.ReadFull(cli.conn, msg.Data)
      	if err != nil {
      		fmt.Println(err.Error())
      	}
      
      	recvData = msg.Data
      	fmt.Printf("==> Client receive Msg: ID = %d, data = %s\n", msg.ID, msg.Data)
      }
      
      
    5. 服务启停

      func (cli *TcpClient) Start(ctx context.Context) error {
      	//go cli.loopSend()
      	cli.waitRecv()
      	return nil
      }
      func (cli *TcpClient) Stop(ctx context.Context) error {
      	//go cli.loopSend()
      	err := cli.conn.Close()
      	if err != nil {
      		return err
      	}
      	return nil
      }
      

三、测试

  • 测试用例

    package tcp
    
    import (
    	"context"
    	"github.com/aceld/zinx/zconf"
    	"github.com/go-nova/pkg/core/transport/tcp/tcp_client"
    	"github.com/go-nova/pkg/core/transport/tcp/tcp_server"
    	"testing"
    	"time"
    )
    
    func TestName(t *testing.T) {
    	var config = &zconf.Config{
    		Host:    "0.0.0.0",
    		TCPPort: 8899,
    	}
    
    	ins := tcp_server.NewServer(config)
    	ins.RegisterRouter(uint32(1002), &tcp_server.RDuplex{})
    	ctx := context.Background()
    	go ins.Start(ctx)
    
    	time.Sleep(time.Second * 10)
    	
    	cli := tcp_client.NewClient(tcp_client.Option{
    		ServerAddr: "127.0.0.1:8899",
    		Retry:      3,
    	})
    	go cli.Start(ctx)
    	go send(cli)
    
    	<-time.After(time.Second * 15)
    	ins.Stop(ctx)
    	cli.Stop(ctx)
    }
    
    func send(cli *tcp_client.TcpClient) {
    	for i := 0; i < 5; i++ {
    		cli.Send([]byte("hello server"))
    	}
    }
    
    
  • 效果

    在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于zinx的go tcp通信案例 的相关文章

  • 运维工程师之-MySQL的故障问题总结

    故障类问题 你在日常工作中遇到过什么故障 你在日常工作中处理过什么故障 你平常工作都干什么活 故障01 mysql时软件版本选择错误 每一个故事的背后都有一个事故 每个故障总结一个故事 软件版本 64位 32位选择错误 故障02 安装故障
  • Java 树结构 TreeNode 表格 工具类

    记录 目录 记录 前言 一 TreeNode 通用树结构使用 1 创建TreeNode树结构基础类 2 创建通用树结构构建类 二 使用步骤 1 通过调用构建类返回树结构 2 测试 总结 前言 本文档基于若依框架编写 项目地址 https g
  • 如何熟练地配置和微调 MacBook Pro 的显示屏幕

    点击右上角 关注 我们 获取更多前沿科技信息 本文共613字 阅读全文约2分钟 关键字 MacBook MacBookPro 苹果系统 Apple 苹果的新款14英寸和16英寸 MacBook Pro 专为专业人士打造 许多的美工或设计师会
  • ChatExcel来了

    chatgpt是一个语言模型 在语言类任务中表现非常好 但是ChatGPT在精准的数据逻辑上表现一般 问chatgpt一些简单的数据处理问题 chatgpt一般还能回答 但chatgpt每次输出的内容有限 日常的数据量至少几百行 这个量级的
  • 应用npm workspace 维护多git仓库的package.json

    1 背景 在大型项目中 随着功能迭代 代码越来越重 需要抽离公用的组件作为子仓库来引用 git submodules 在项目中拥有多个包 每个包的package json较难维护 使用npm workspace可以解决这个问题 2 npm
  • Spring Security OAuth2.0(五)-----OAuth2实现自定义统一认证登录页/自定义授权页/基于mysql存储数据

    本次实例涉及三个项目 核心项目工程unify authorization server 认证授权登录 资源服务器项目unify resource server 测试项目是前面几篇写的项目 这里没有改动直接用来测试实例项目 一 unify a
  • 区块链中的签名怎么签?

    想知道更多区块链技术知识 请百度 链客区块链技术问答社区 链客 有问必答 明星的签名在粉丝的眼中视若无价 生意场上的签名被视为不可抵赖 而在区块链中 数字签名 也是一个独一无二的数值 如今网络环境愈发宽泛 大量的信息通过网络传播留下痕迹 人
  • ACCESS中用SUM()函数的精度问题

    链接来自 https zhidao baidu com question 74046761 html 我在access中使用sum函数时也遇到了该问题 明明数据表中存储的数据是两位小数 通过select value from t table

随机推荐

  • 佐美人--arm32/64/openwrt文件系统移植

    为了让不在OpenWrt项目支持列表中的ARM机器快速使用OpenWrt 可以用替换rootfs的简易方法进行移植 首先 确保你的ARM盒子有能正常使用的Linux系统 并且最好有良好的社区支持 可以去armbian寻找有开源支持的开发板
  • TS泛型用法

    泛型 可以理解为更广泛的类型 也就是说我们在函数 接口 类等中 约束数据类型的时候 可以通过泛型的方式来实现类型的传参 让数据的类型也可以根据传递的类型值来控制 一 函数中的泛型 1 定义泛型函数 基础语法 function 函数名 lt
  • python---之plt.subplot画图详解

    转载 https www cnblogs com nju2014 p 5620776 html Matplotlib 详解图像各个部分 首先一幅Matplotlib的图像组成部分介绍 在matplotlib中 整个图像为一个Figure对象
  • 关于word中插入知网e-study插件问题

    写论文过程中难免会出现word中e study莫名其妙的被禁止 估计是被杀毒软件或启动项什么的优化禁止了 打开word gt word选项 gt 加载项 gt 管理 gt 禁用项目 gt 把e study相关插件删除 在COM 加载项中将
  • Python温习(四)——编程常识与正则

    基础功能 Python中 前面已经创建了变量类型并赋值存在的对象 下次再进行使用的时候 不需要重新再次进行输入 只需要进行输入前两个字母 以Tab键进行历史对象查找后 进行切换回车 1 input和print输入 输出 da input 请
  • 2019-2020-1 1823《程序设计与数据结构》第二、三周作业总结

    作业地址 第二 三周作业总结 https edu cnblogs com campus besti 2019 2020 1 1823 PDDS homework 7585 提交情况如图 忘记提交作业 已在博客分中扣除相应的分数 作业问题 优
  • 2023华为OD机试真题-分界线(JAVA、Python、C++)

    题目描述 电视剧 分界线 里面有一个片段 男主为了向警察透露案件细节 且不暴露自己 于是将报刊上的字剪切下来 剪拼成匿名信 现在有一名举报人 希望借鉴这种手段 使用英文报刊完成举报操作 但为了增加文章的混淆度 只需满足每个单词中字母数量一致
  • sqlmap详细使用教程

    文章目录 简介 SQL注入 流程 命令参数 拓展 SQLmap用户手册 简介 Sqlmap是一个自动化检测和利用SQL注入漏洞的免费开源工具 对SQL注入漏洞进行检测的最佳工具 支持对多种数据库进行注入测试 能够自动识别数据库类型并注入 支
  • 买卖股票类问题动态规划解法(Leetcode题解-Python语言)

    在 Leetcode 中 关于买卖股票的问题共有6道 而这些题目是可以用相同的思维进行求解的 强烈推荐这篇总结 写得非常到位 股票类问题的动态规划分三步走 1 首先明确方程的含义 T i k 0 表示在第 i 天结束时 最多进行 k 次交易
  • 架构演变

    一 传统架构方式 最初做项目时 架构一般都会分为3层 即表现层展示系统界面 业务层处理各种业务逻辑 持久层操作来源于数据库中的数据 数据库中则存储我们需要存储的数据 这种三层架构的方式适用于大多数项目 但这种方法还不能称之为架构 我们做的时
  • PyTorch中张量的shape和stride的关系

    个人总结 以下是juppyter notebook下的实验
  • Web安全常见漏洞原理、危害及其修复建议

    web安全常见漏洞原理 危害及其修复建议 一 SQL注入漏洞 原理 危害 修复建议 二 XSS漏洞 原理 危害 修复建议 三 CSRF漏洞 原理 危害 修复建议 四 SSRF漏洞 原理 危害 预防建议 五 文件上传漏洞 原理 危害 修复建议
  • 弗洛伊德算法(floyd)

    算法背景 图中的A B C D E F G 代表7个村庄 边上的权值带表两村庄之间的距离 现在要从某一个村庄 例如G村庄 往另外几个村庄送邮件 问任意一村庄到其他各村庄的最短距离分别是多少 思路 该问题实际是求从任一顶点到其余顶点的最短距离
  • 揭秘京东城市时空数据引擎—JUST如何助力交通流量预测

    2014年跨年夜上海外滩人流隐患事件 使得公共安全问题受到了全体社会的广泛关注 解决这一问题的很重要一项工作就是 如何实时监控和快速预测城市中每个地方的人流量 当某个地方的人流量超过给定的值或者有超过给定值的趋势时 相关部门能及时地采取相关
  • Python学习笔记(六):数据可视化

    1 使用matplotlib绘制图形 1 1 绘制折线图 import matplotlib pyplot as plt b 1 2 3 4 5 6 7 a 1 4 9 16 25 36 49 plt plot b a linewidth
  • js在控制台输出菱形

    js在控制台输出菱形 以一个上半部分10行 下半部分9行的为例 var str 在控制台输出要采用字符串拼接 所以先定义一个空字符串 for var row 1 row lt 10 row 外层循环控制行数 先输出上半部分的10行 for
  • HTTPOXY -- CGI 环境变量劫持漏洞分析

    0x00 前言 昨晚 一个名为 HTTPOXY 的漏洞在安全圈内广泛传播 云盾攻防对抗团队第一时间对此漏洞进行了深入分析 发现其本质是一个 CGI 环境变量劫持漏洞 对 CGI 的环境变量 HTTP PROXY 变量进行劫持 如果 CGI
  • Python作业

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 python安装步骤 打开官网 https www python org downloads windows 下载中心 测试安装是否成功 windows gt 运行
  • BurpSuite学习:在火狐浏览器使用foxyproxy添加代理127.0.0.1后无法正常上网

    个人认为 因为127 0 0 1就是本机上的本地服务器 它应该不具备服务器的功能 所以浏览器向本地服务器发送请求也不会转发到外网 更不会得到回应 打开burpsuite 它会承担服务器的作用转发请求 这时候浏览器会显示应该是请求被拦截之类的
  • 基于zinx的go tcp通信案例

    基于zinx的go tcp通信示例 一 zinx简介 https gitee com Aceld zinx Zinx是一个基于Golang的轻量级tcp服务框架 根据官方的定位 zinx是在游戏领域或者其他长链接的领域的轻量级企业框架 其使