您现在的位置是:首页 >技术杂谈 >基于zinx的go tcp通信案例网站首页技术杂谈
基于zinx的go tcp通信案例
简介基于zinx的go tcp通信案例
基于zinx的go tcp通信示例
一、zinx简介:(https://gitee.com/Aceld/zinx/)
Zinx是一个基于Golang的轻量级tcp服务框架,根据官方的定位,zinx是在游戏领域或者其他长链接的领域的轻量级企业框架,其使用简单,性能高效,能够很方便的帮助用户搭建tcp通信服务。
一个简单的zinx-tcp服务搭建只需要三步:
- 创建server服务实例
- 配置自定义路由及业务
- 启动服务
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工具包
-
tcp-server服务端封装
-
配置注入
//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 }
-
服务实例化
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 }
-
路由注册(消息收发)
// 路由注册入口 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 ", request.GetMsgID(), string(request.GetData())) err := request.GetConnection().SendMsg(2, []byte("hello zix hello Router")) if err != nil { fmt.Println(err) } }
-
服务启动/停止
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 }
-
-
tcp-client服务端封装
-
配置注入
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 }
-
服务实例化
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 }
-
服务监听
func (cli *TcpClient) waitRecv() { for { select { case <-cli.revChan: go cli.recv() } } }
-
消息收发
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 ", msg.ID, msg.Data) }
-
服务启停
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")) } }
-
效果
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。