Zinx框架学习 - 链接封装与业务绑定

文章介绍了Zinx框架中V0.2版本对客户端链接的接口封装和业务处理。通过创建IConneciton接口定义了链接的基本操作,如Start和Stop,并定义了HandleFunc处理业务的函数接口。Connection结构体实现了接口,包括连接的读写业务方法,以及与Server的绑定。在Server中,新连接通过AcceptTCP获取,然后与CallBackToClient处理方法绑定,启动读取和回显数据的业务逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Zinx - V0.2 链接封装与业务绑定

  • 之前的v0.1版本,已经实现了一个基础的Server框架,现在需要对客户端链接和不同的客户端链接锁处理的不同业务再做一层接口封装
  • 在ziface下创建一个属于链接的接口文件iconnection.go,znet下创建文件connection.go实现链接接口

连接模块实现思路

代码实现

新增iconnection链接接口:定义链接的方法和处理连接绑定业务的方法

package ziface

import "net"

//定义链接模块的抽象层
type IConneciton interface {
	//启动链接 让当前的链接准备开始工作
	Start()

	//停止链接 结束当前链接的工作
	Stop()

	//获取当前链接的绑定socket conn
	GetTCPConnection() *net.TCPConn

	//获取当前链接模块的链接ID
	GetConnID() uint32

	//获取远程客户端的 TCP状态 IP port
	RemoteAddr() net.Addr

	//发送数据, 将数据发送给远程的客户端
	Send(data []byte) error
}

//定义一个处理链接业务的方法
type HandleFunc func(*net.TCPConn, []byte, int) error
  • 关于HandFunc的函数说明:type HandleFunc func(*net.TCPConn, []byte, int) error

        这个HandFunc是一个函数类型,是所有conn链接在处理业务的函数接口
                第一个参数:socket原生链接
                第二个参数:客户端请求的数据
                第三个参数:客户端请求的数据长度
        这样如果我们想要指定一个conn的处理业务,只需要定义一个HandFunc类型的函数,就可以和该链接绑定了

新增connection链接实现:实现链接

然后开始实现连接的方法和属性,提供一个初始化连接模块的方法NewConnection(),需要注意的是当框架启动时调用Start方法尝试开启两个Goroutine,分别是从客户端读的Goroutine和从客户端写的Goroutine,我们这里先把读写业务写在一个Goroutine中,后面再分开

package znet

import (
	"fmt"
	"net"
	"zinx/ziface"
)

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

	//链接的ID
	ConnID uint32

	//当前的链接状态
	isClosed bool

	//当前链接所绑定的处理业务方法API
	handleAPI ziface.HandleFunc

	//告知当前链接已经退出的/停止 channel
	ExitChan chan bool
}

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

//链接的读业务方法
func (c *Connection) StartReader() {
	fmt.Println(" Reader Goroutine is running...")
	defer fmt.Println("connID = ", c.ConnID, " Reader is exit, remote addr is ", c.RemoteAddr().String())
	defer c.Stop()

	for {
		//读取客户端的数据到buf中, 最大512字节
		buf := make([]byte, 512)
		cnt, err := c.Conn.Read(buf)
		if err != nil {
			fmt.Println("recv buf err", err)
			continue
		}

		//调用当前链接所绑定的HandleAPI
		if err := c.handleAPI(c.Conn, buf, cnt); err != nil {
			fmt.Println("ConnID ", c.ConnID, " handle is error", err)
			break
		}
	}
}

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

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

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

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

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

//获取当前链接的绑定socket conn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

//获取当前链接模块的链接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

//获取远程客户端的 TCP状态 IP port
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

//发送数据, 将数据发送给远程的客户端
func (c *Connection) Send(data []byte) error {
	return nil
}

接下来就要将connection和server进行绑定,我们可以将server.go文件中Start()方法的第三步的conn句柄和封装好的connection模块进行绑定,我们可以将“已经与客户端建立连接,做一些业务,做一个最基本的最大的512字节长度的回显业务”这部分内存交给connection模块进行处理,在server.go提供一个HandlerFunc类型的callback_api函数CallBackToClient()方法,这个方法用来定义当前客户端链接的所绑定handle api(目前这个handle是写死的,以后优化应该由用户自定义handle方法)

		//3 阻塞的等待客户端链接,处理客户端链接业务(读写)
		for {
			//如果有客户端链接过来,阻塞会返回
			conn, err := listenner.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}

			// 将处理新连接的业务方法 和 conn 进行绑定 得到我们的链接模块
			dealConn := NewConnection(conn, cid, CallBackToClient)
			cid++

			// 启动当前的链接业务处理
			go dealConn.Start()
		}
// 定义当前客户端链接的所绑定handle api(目前这个handle是写死的,以后优化应该由用户自定义handle方法)
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
}

整体思路

        我们在启动业务的时候调用server.go中的Start()方法,监听服务器地址,当客户端连接建立成功后会得到conn句柄,通过conn句柄和CallBackToClient()方法绑定在一起得到一个dealconn,然后开启一个Goroutine调用connection模块的Start()方法,开启StartReader()协程,这个协程首先会从客户端读512字节的数据,然后调用handleAPI处理数据,即在客户端定义好的CallBackToClient()方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值