前言
在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)
}
}