zinxv0.2 简单的链接封装和业务绑定

2020-04-27  本文已影响0人  茶艺瑶

这里我们需要实现的功能有以下


image.png

在本章中,我们需要实现的修改Server方法中的,链接处理,修改一堆代码

go func() {
        //获取一个TCP的Addr
        addr,err := net.ResolveTCPAddr(this.IPVersion,fmt.Sprintf("%s:%d",this.IP,this.Port))
        if err!=nil{
            fmt.Println("resolve tcp addr error:",err)
        }
        //监听路由的地址
        listen,err := net.ListenTCP(this.IPVersion,addr)
        if err!=nil{
            fmt.Println("Listen",this.IPVersion,"err",err)
            return
        }

        fmt.Println("start zinx server succ",this.Name,"succ,Listening..")

        var cid uint32
        cid = 0

        //阻塞的等待客户端的链接,处理业务
        for {
            conn,err := listen.AcceptTCP()
            if err!=nil {
                fmt.Println("Accept err",err)
                continue
            }

            //客户端已经建立链接,做一些业务,因为比较简单,所以就回写吧
            dealConn := NewConnection(conn,cid,CallBackToClient)
            cid++

            //启动当前业务
            go dealConn.Start()

        }
    }()

如果所示,我们需要一个定义一下我们的Connection基本接口

package ziface

import "net"

//定义链接模块的抽象层
type IConnection interface {
    //启动链接 让当前的链接业务开始工作
    Start()
    //停止链接
    Stop()
    //获取当前链接socket conn
    GetTCPConnection() *net.TCPConn
    //获取链接ID
    GetConnID() uint32
    //获取客户的TCP IP port
    RemoteAddr() net.Addr
    //发送数据,将数据发送远程的客户端
    Send(data []byte)
}

//定义一个处理业务的方法
type HandleFunc func(*net.TCPConn,[]byte,int) error

和一个实现链接消息处理的对象

package znet

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

/**
    链接模块
 */
type Connection struct {
    //当前链接Socket TCP
    Conn *net.TCPConn

    //链接的ID
    ConnID uint32

    //当前链接的状态
    isClosed bool

    //当前链接的处理方法
    handleAPI ziface.HandleFunc

    //退出channel
    ExitChan chan bool
}

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

    return c
}

/**
    链接的读业务方法
 */
func (c *Connection) StartReader()  {
    fmt.Println("Reader Goroutine is running...")
    defer fmt.Println("c.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(){

    //如果当前链接已经关闭
    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
}

最后我们需要回到Server.go 中修改成以下代码

package znet

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

// IServer的接口实现,定义一个Server的服务器模块
type Server struct {
    //服务器名称
    Name string
    //服务器ip版本
    IPVersion string
    //服务器监听ip
    IP string
    //端口
    Port int
}

func (this *Server) Start() {
    fmt.Printf("[Start] string Listenner at IP: %s,Prot %d,is start \n",this.IP,this.Port)

    //可以不阻塞
    go func() {
        //获取一个TCP的Addr
        addr,err := net.ResolveTCPAddr(this.IPVersion,fmt.Sprintf("%s:%d",this.IP,this.Port))
        if err!=nil{
            fmt.Println("resolve tcp addr error:",err)
        }
        //监听路由的地址
        listen,err := net.ListenTCP(this.IPVersion,addr)
        if err!=nil{
            fmt.Println("Listen",this.IPVersion,"err",err)
            return
        }

        fmt.Println("start zinx server succ",this.Name,"succ,Listening..")

        var cid uint32
        cid = 0

        //阻塞的等待客户端的链接,处理业务
        for {
            conn,err := listen.AcceptTCP()
            if err!=nil {
                fmt.Println("Accept err",err)
                continue
            }

            //客户端已经建立链接,做一些业务,因为比较简单,所以就回写吧
            dealConn := NewConnection(conn,cid,CallBackToClient)
            cid++

            //启动当前业务
            go dealConn.Start()

        }
    }()

}

func CallBackToClient (conn *net.TCPConn,data []byte,cnt int)  error {
    //回显的业务
    fmt.Println("[Conn Handle] CallbackToClient...")
    if _,err:=conn.Write(data[:cnt]);err!=nil{
        return  errors.New("CallBackToClient error")
    }

    return nil
}


func (this *Server) Stop() {
    //TODO 将以西服务资源,回收
}

func (this *Server) Serve() {
    //启动服务
    this.Start()

    //TODO 启动服务后做一些额外的业务功能

    //阻塞状态
    select {

    }
}

/**
    构造函数
 */
func NewServer(name string) ziface.IServer  {
    s:= &Server{
        Name:name,
        IPVersion:"tcp4",
        IP:"0.0.0.0",
        Port:8999,
    }
    return  s
}
















上一篇 下一篇

猜你喜欢

热点阅读