目录
- 前言
- 一、IRequest消息请求抽象类
-
- 1 - IRequest需求分析
- 2 - irequest.go
- 3 - request.go
- 二、router路由模块
-
- 1 - router模块分析
- 2 - irouter.go
- 3 - router.go
- 三、源码修改
- 四、Router模块总结
-
- 六、完整源码
-
- 1 - ziface接口
- 2 - znet实现
- 3 - 测试类
前言
- 在zinxV0.2中conn链接的业务处理HandleFunc是固定写死的,接下来我们需要自定义一个conn处理业务的接口
- 需要定义一些interface来让用户填写任意格式的链接处理业务方法
一、IRequest消息请求抽象类
1 - IRequest需求分析
- IRequest:把客户端请求的连接信息 和 请求的数据,放在一个叫Request的请求类里,这样的好处是我们可以从Request里得到全部客户端的请求信息;每次客户端的全部请求数据,Zinx都会把它们一起放到一个Request结构体里

2 - irequest.go
package ziface
type IRequest interface {
GetConnection() IConneciton
GetData() []byte
}
3 - request.go
package znet
import (
"zinx/ziface"
)
type Request struct {
conn ziface.IConneciton
data []byte
}
func (r *Request) GetConnection() ziface.IConneciton {
return r.conn
}
func (r *Request) GetData() []byte {
return r.data
}
二、router路由模块
1 - router模块分析
- router模块的作用:服务端应该给zinx框架配置当前链接的处理业务方法;之前conn链接的业务处理HandleFunc是固定写死的,现在是可以⾃定义,并且有3种接⼝可以重写(每个⽅法都有⼀个唯⼀的形参 IRequest 对象,也就是客户端请求过来的连接和请求数据,作为业务⽅法的输⼊数据)
- Handle :是处理当前链接的主业务函数
- PreHandle :如果需要在主业务函数之前有前置业务,可以重写这个⽅法
- PostHandle :如果需要在主业务函数之后⼜后置业务,可以重写这个⽅法
2 - irouter.go
package ziface
type IRouter interface {
PreHandle(request IRequest)
Handle(request IRequest)
PostHandle(request IRequest)
}
3 - router.go
package znet
import "zinx/ziface"
type BaseRouter struct{}
func (br *BaseRouter) PreHandle(request ziface.IRequest) {}
func (br *BaseRouter) Handle(request ziface.IRequest) {}
func (br *BaseRouter) PostHandle(request ziface.IRequest) {}
三、源码修改
- 1-新增请求接口ziface/irequest.go
- 2-新增请求接口实现znet/request.go
- 3-新增路由接口ziface/irouter.go
- 4-新增路由接口实现znet/router.go
- 5-ziface/iserver.go增加抽象方法AddRouter:让zinx使用者可以自定义一个router处理业务方法
package ziface
type IServer interface {
Start()
Stop()
Serve()
AddRouter(router IRouter)
}
- 6-znet/server.go实现抽象方法AddRouter
func (s *Server) AddRouter(router ziface.IRouter) {
s.Router = router
fmt.Println("Add Router Succ!!")
}
- 7-znet/server.go添加router成员
type Server struct {
Name string
IPVersion string
IP string
Port int
Router ziface.IRouter
}
- 8-znet/connection.go添加router成员并修改初始化链接方法
type Connection struct {
Conn *net.TCPConn
ConnID uint32
isClosed bool
ExitChan chan bool
Router ziface.IRouter
}
func NewConnection(conn *net.TCPConn, connID uint32, router ziface.IRouter) *Connection {
c := &Connection{
Conn: conn,
ConnID: connID,
Router: router,
isClosed: false,
ExitChan: make(chan bool, 1),
}
return c
}
- 9-znet/connection.go的StartReader方法中:初始化一个request,开启goroutine调用路由业务
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 := make([]byte, 512)
_, err := c.Conn.Read(buf)
if err != nil {
fmt.Println("recv buf err", err)
continue
}
req := Request{
conn: c,
data: buf,
}
go func(request ziface.IRequest) {
c.Router.PreHandle(request)
c.Router.Handle(request)
c.Router.PostHandle(request)
}(&req)
}
}
- 10-修改测试类server.go:实现自定义的Router
package main
import (
"fmt"
"zinx/ziface"
"zinx/znet"
)
type PingRouter struct {
znet.BaseRouter
}
func (this *PingRouter) PreHandle(request ziface.IRequest) {
fmt.Println("Call Router PreHandle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("before ping...\n"))
if err != nil {
fmt.Println("call back before ping error")
}
}
func (this *PingRouter) Handle(request ziface.IRequest) {
fmt.Println("Call Router Handle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("ping...ping...ping\n"))
if err != nil {
fmt.Println("call back ping...ping...ping error")
}
}
func (this *PingRouter) PostHandle(request ziface.IRequest) {
fmt.Println("Call Router PostHandle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("after ping\n"))
if err != nil {
fmt.Println("call back after ping error")
}
}
func main() {
s := znet.NewServer("[zinx V0.3]")
s.AddRouter(&PingRouter{})
s.Serve()
}
四、Router模块总结
1 - 总结xmind

2 - 项目结构

六、完整源码
1 - ziface接口
package ziface
type IServer interface {
Start()
Stop()
Serve()
AddRouter(router IRouter)
}
package ziface
type IRouter interface {
PreHandle(request IRequest)
Handle(request IRequest)
PostHandle(request IRequest)
}
package ziface
type IRequest interface {
GetConnection() IConneciton
GetData() []byte
}
package ziface
import "net"
type IConneciton interface {
Start()
Stop()
GetTCPConnection() *net.TCPConn
GetConnID() uint32
RemoteAddr() net.Addr
Send(data []byte) error
}
type HandleFunc func(*net.TCPConn, []byte, int) error
2 - znet实现
package znet
import (
"fmt"
"net"
"zinx/ziface"
)
type Server struct {
Name string
IPVersion string
IP string
Port int
Router ziface.IRouter
}
func (s *Server) Start() {
fmt.Printf("[Start] Server Listenner at IP :%s, Port %d, is starting\n", s.IP, s.Port)
go func() {
addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
if err != nil {
fmt.Println("resolve tcp addt error : ", err)
return
}
listenner, err := net.ListenTCP(s.IPVersion, addr)
if err != nil {
fmt.Println("listen ", s.IPVersion, " err ", err)
return
}
fmt.Println("start Zinx server succ, ", s.Name, " succ, Listenning...")
var cid uint32
cid = 0
for {
conn, err := listenner.AcceptTCP()
if err != nil {
fmt.Println("Accept err", err)
continue
}
dealConn := NewConnection(conn, cid, s.Router)
cid++
go dealConn.Start()
}
}()
}
func (s *Server) Stop() {
}
func (s *Server) Serve() {
s.Start()
select {}
}
func (s *Server) AddRouter(router ziface.IRouter) {
s.Router = router
fmt.Println("Add Router Succ!!")
}
func NewServer(name string) ziface.IServer {
s := &Server{
Name: name,
IPVersion: "tcp4",
IP: "0.0.0.0",
Port: 8999,
Router: nil,
}
return s
}
package znet
import "zinx/ziface"
type BaseRouter struct{}
func (br *BaseRouter) PreHandle(request ziface.IRequest) {}
func (br *BaseRouter) Handle(request ziface.IRequest) {}
func (br *BaseRouter) PostHandle(request ziface.IRequest) {}
package znet
import (
"zinx/ziface"
)
type Request struct {
conn ziface.IConneciton
data []byte
}
func (r *Request) GetConnection() ziface.IConneciton {
return r.conn
}
func (r *Request) GetData() []byte {
return r.data
}
package znet
import (
"fmt"
"net"
"zinx/ziface"
)
type Connection struct {
Conn *net.TCPConn
ConnID uint32
isClosed bool
ExitChan chan bool
Router ziface.IRouter
}
func NewConnection(conn *net.TCPConn, connID uint32, router ziface.IRouter) *Connection {
c := &Connection{
Conn: conn,
ConnID: connID,
Router: router,
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 := make([]byte, 512)
_, err := c.Conn.Read(buf)
if err != nil {
fmt.Println("recv buf err", err)
continue
}
req := Request{
conn: c,
data: buf,
}
go func(request ziface.IRequest) {
c.Router.PreHandle(request)
c.Router.Handle(request)
c.Router.PostHandle(request)
}(&req)
}
}
func (c *Connection) Start() {
fmt.Println("Conn Start() ... ConnID = ", c.ConnID)
go c.StartReader()
}
func (c *Connection) Stop() {
fmt.Println("Conn Stop().. ConnID = ", c.ConnID)
if c.isClosed == true {
return
}
c.isClosed = true
c.Conn.Close()
close(c.ExitChan)
}
func (c *Connection) GetTCPConnection() *net.TCPConn {
return c.Conn
}
func (c *Connection) GetConnID() uint32 {
return c.ConnID
}
func (c *Connection) RemoteAddr() net.Addr {
return c.Conn.RemoteAddr()
}
func (c *Connection) Send(data []byte) error {
return nil
}
3 - 测试类
package main
import (
"fmt"
"zinx/ziface"
"zinx/znet"
)
type PingRouter struct {
znet.BaseRouter
}
func (this *PingRouter) PreHandle(request ziface.IRequest) {
fmt.Println("Call Router PreHandle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("before ping...\n"))
if err != nil {
fmt.Println("call back before ping error")
}
}
func (this *PingRouter) Handle(request ziface.IRequest) {
fmt.Println("Call Router Handle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("ping...ping...ping\n"))
if err != nil {
fmt.Println("call back ping...ping...ping error")
}
}
func (this *PingRouter) PostHandle(request ziface.IRequest) {
fmt.Println("Call Router PostHandle...")
_, err := request.GetConnection().GetTCPConnection().Write([]byte("after ping\n"))
if err != nil {
fmt.Println("call back after ping error")
}
}
func main() {
s := znet.NewServer("[zinx V0.3]")
s.AddRouter(&PingRouter{})
s.Serve()
}
package main
import (
"fmt"
"net"
"time"
)
func main() {
fmt.Println("client start...")
time.Sleep(1 * time.Second)
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
fmt.Println("client start err, exit!")
return
}
for {
_, err := conn.Write([]byte("Hello Zinx V0.2.."))
if err != nil {
fmt.Println("write conn err", err)
return
}
buf := make([]byte, 512)
cnt, err := conn.Read(buf)
if err != nil {
fmt.Println("read buf error")
return
}
fmt.Printf(" server call back: %s, cnt = %d\n", buf, cnt)
time.Sleep(1 * time.Second)
}
}