【zinx】Golang轻量级TCP服务器框架(三)—— 基础request封装以及router模块绑定

Golang轻量级TCP服务器框架(三)—— 基础request封装以及router模块绑定

原作者视频地址:zinx-Golang轻量级TCP服务器框架
本人为自学整理的文档,梳理思考开发框架的基本思路,方法,以及视频中不理解的地方。
若想学习,强烈建议直接观看原作视频即可。
可在下方留言交流。

1.思路

想必大家都用过go语言得http吧,go的http消息都会被封装为http.Request。这里我们也做一下类似的封装。
如下图所示:
1

① 客户端与server建立链接之后
② server会为其创建connection的链接封装,也就是前两篇的内容
③ 这个时候,对于这一个conn链接,会发送过来n多包的消息(请求),所以这里,我们需要再次对这些消息(请求)进行封装。
④ 我们再想一下,这里n多的消息(请求),不会像http那样能分辨出是put、get…等命令,再或者我们还想增加一下新的命令:也就是说,消息发送过来,我们解析之后,可以为不同的命令绑定不同的路由方法。再或者我们可以根据该客户端属性的不同,让其只能执行相应的路由方法。

所以,本节我们需要实现两个基本接口irequest和irouter方法。(当然,这里也仅仅是一个循序渐进的过程,后续也会对这里进行更改。)

1.1 整体思路图

23

2.irquest接口的设计

抽象实现

type IRequest interface {
	//得到当前链接
	GetConnection() IConnection
	//得到当前数据
	GetData() []byte
}

具体实现

type request struct {
	//已经和client建立好的链接
	conn ziface.IConnection
	//客户端请求的数据
	data []byte
}

//得到当前链接
func (r *request) GetConnection() ziface.IConnection{
	return r.conn
}
//得到当前数据
func (r *request) GetData() []byte {
	return r.data
}

这块没什么好说的。

3.irouter接口的设计

抽象实现

type IRouter interface {
	//处理conn业务之前的钩子方法hook
	PreHandle(request IRequest)
	//处理conn业务的主方法hook
	Handle(request IRequest)
	//处理conn业务之后的钩子方法hook
	PostHandle(request IRequest)
}

具体实现

//实现router的时候,可以先将BaseRouter作为基类嵌入其中,然后只需要重写其方法即可

type BaseRouter struct { }


//处理conn业务之前的钩子方法hook
func (br *BaseRouter) PreHandle(request ziface.IRequest){

}
//处理conn业务的主方法hook
func (br *BaseRouter) Handle(request ziface.IRequest){

}
//处理conn业务之后的钩子方法hook
func (br *BaseRouter) PostHandle(request ziface.IRequest){

}

在具体实现中,我们不需要去对函数做具体实现,为什么呢?

  1. 首先,路由方法,不可能仅仅一种方式,可能会有好几个。这样的话,我们只需要让,不同的路由结构体去将BaseRouter作为基类,然后重写它的方法即可。
  2. 其次,也就是作者说的,可能我们根本不需要业务之前、业务之后的方法,此时,我们不去重写它们即可。

4.server如何集成router模块

这里也算是一个关键,如何将我们写的模块,集成到原来的框架中呢?

  1. iserver中添加一个router接口,因为我们需要用户,将其自定义的路由方法绑定到这个server服务器。同时,还要在server中添加router成员。如下:
type IServer interface {
	Start()
	Server()
	Stop()

	//路由功能:给当前服务注册一个路由方法
	AddRouter(router IRouter)
}
type server struct {
	//服务器的名称
	name string
	//ip的版本
	ipVersion string
	//ip地址
	ip string
	//ip监听端口
	port int
	//路由(后期可配置多个router)
	Router ziface.IRouter
}
  1. connection中我们也要添加router成员。
type connection struct {
	//当前链接的socket TCP套接字
	conn *net.TCPConn
	//当前链接ID
	connID uint32
	//当前链接是否关闭
	isClosed bool
	//通知当前链接已经退出/停止的channel
	exitChan chan bool
	//路由(后期可配置多个router)
	Router ziface.IRouter
}
  1. 将server中绑定的路由方法,再次绑定到connection。需要修改server中的start函数。
		//3.阻塞的等待客户端连接,处理客户端业务
		for {
			conn, err := listenner.AcceptTCP()
			if err != nil {
				fmt.Println("[ERROR] Accept client conn is error :", err)
				continue
			}

//这里的第三个参数
//上一节中,第三个参数是直接绑定了一个方法,但是并不允许用户自定义。
*			dealConn := NewConnection(conn, cid, s.Router) 
			cid++
			go dealConn.Start()
		}
  1. 在connection中如何调用,这里我们修改StartReader函数。

注释的部分是上一节的实现,这里我们把数据封装到request中,再让conn中注册的路由方法,去调用request。
与上一篇不同的是,这个路由函数用户可以自己定义,更加清晰。后期甚至可以变成不同客户端不同路由方法,不同命令不同路由方法,都是可以的(本节并未实现,目前一个server只能绑定一个router)。

	for {
		buf := make([]byte, 512)
		_ , err := c.conn.Read(buf)
		if err != nil {
			fmt.Println("connID = ", c.connID,"recv is err :",err)
			continue
		}
		
		//当用当前链接绑定的handel
		//err = c.handleFunc(c.conn, buf, cnt)
		//if err != nil {
		//	fmt.Println("connID = ", c.connID,"handle is err :",err)
		//	break   //这里的话,直接break,或者contine都是可以的,根据自己的实际业务编写
		
		req := &request{
			conn: c,
			data: buf,
		}

		//执行注册的路由方法
		go func(request ziface.IRequest) {
			c.Router.PreHandle(request)
			c.Router.Handle(request)
			c.Router.PostHandle(request)
		}(req)
	}

5.用户调用测试程序

上边已经将request和router即成到了框架中,那么我们该如何使用呢?
客户端代码无需改变。
server端代码如下:

package main

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

type PingRouter struct {    //1.这里继承BaseRouter基类,及其进行重写。用户自定义的重写。
	znet.BaseRouter
}

func (p *PingRouter) PreHandle(request ziface.IRequest){
	fmt.Println("[conn PreHandle ...]")
	_, err := request.GetConnection().GetTCPConnection().Write([]byte("   PrePing return   "))
	if err != nil {
		fmt.Println("PrePing return is err :",err)
	}
}

func (p *PingRouter) Handle(request ziface.IRequest){
	fmt.Println("[conn Handle ...]")
	_, err := request.GetConnection().GetTCPConnection().Write(request.GetData())
	if err != nil {
		fmt.Println("Ping return is err :",err)
	}
}

func (p *PingRouter) PostHandle(request ziface.IRequest){
	fmt.Println("[conn PostHandle ...]")
	_, err := request.GetConnection().GetTCPConnection().Write([]byte("   PostPing return   "))
	if err != nil {
		fmt.Println("PostPing return is err :",err)
	}
}

func main() {
	//1.创建服务端
	s := znet.NewServer("[zinxv1.0]")
	s.AddRouter(&PingRouter{})      //2.将用户自定义的路由方法,绑定到server服务器
	//2.启动server
	s.Server()
}

实验结果:
3

6.总结

不再贴出完整的代码,因为功能尚未完善

本节的话,最重要的就是router的设计思路,能够实现用户自定义方法。
就是好比,用户去写了一套模板,可以给各个request去使用。
作者说是一种设计模式。
本节只是实现了最基本的router功能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋山刀名鱼丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值