zinx/znet/server.go
package znetimport ("fmt""net""time""zinx/ziface")//iServer 接口实现,定义一个Server服务类type Server struct {//服务器的名称Name string//tcp4 or otherIPVersion string//服务绑定的IP地址IP string//服务绑定的端口Port int//当前Server由用户绑定的回调router,也就是Server注册的链接对应的处理业务Router ziface.IRouter}/*创建一个服务器句柄*/func NewServer (name string) ziface.IServer {s:= &Server {Name :name,IPVersion:"tcp4",IP:"0.0.0.0",Port:7777,Router: nil,}return s}//============== 实现 ziface.IServer 里的全部接口方法 ========//开启网络服务func (s *Server) Start() {fmt.Printf("[START] Server listenner at IP: %s, Port %d, is starting\n", s.IP, s.Port)//开启一个go去做服务端Linster业务go func() {//1 获取一个TCP的Addraddr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))if err != nil {fmt.Println("resolve tcp addr err: ", err)return}//2 监听服务器地址listenner, err:= net.ListenTCP(s.IPVersion, addr)if err != nil {fmt.Println("listen", s.IPVersion, "err", err)return}//已经监听成功fmt.Println("start Zinx server ", s.Name, " succ, now listenning...")//TODO server.go 应该有一个自动生成ID的方法var cid uint32cid = 0//3 启动server网络连接业务for {//3.1 阻塞等待客户端建立连接请求conn, err := listenner.AcceptTCP()if err != nil {fmt.Println("Accept err ", err)continue}//3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接//3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的dealConn := NewConntion(conn, cid, s.Router)cid ++//3.4 启动当前链接的处理业务go dealConn.Start()}}()}func (s *Server) Stop() {fmt.Println("[STOP] Zinx server , name " , s.Name)//TODO Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理}func (s *Server) Serve() {s.Start()//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加//阻塞,否则主Go退出, listenner的go将会退出for {time.Sleep(10*time.Second)}}//路由功能:给当前服务注册一个路由业务方法,供客户端链接处理使用func (s *Server)AddRouter(router ziface.IRouter) {s.Router = routerfmt.Println("Add Router succ! " )}
zinx/znet/conneciont.go
package znetimport ("fmt""net""zinx/ziface")type Connection struct {//当前连接的socket TCP套接字Conn *net.TCPConn//当前连接的ID 也可以称作为SessionID,ID全局唯一ConnID uint32//当前连接的关闭状态isClosed bool//该连接的处理方法routerRouter ziface.IRouter//告知该链接已经退出/停止的channelExitBuffChan chan bool}//创建连接的方法func NewConntion(conn *net.TCPConn, connID uint32, router ziface.IRouter) *Connection{c := &Connection{Conn: conn,ConnID: connID,isClosed: false,Router: router,ExitBuffChan: make(chan bool, 1),}return c}func (c *Connection) StartReader() {fmt.Println("Reader Goroutine is running")defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")defer c.Stop()for {//读取我们最大的数据到buf中buf := make([]byte, 512)_, err := c.Conn.Read(buf)if err != nil {fmt.Println("recv buf err ", err)c.ExitBuffChan <- truecontinue}//得到当前客户端请求的Request数据req := Request{conn:c,data:buf,}//从路由Routers 中找到注册绑定Conn的对应Handlego func (request ziface.IRequest) {//执行注册的路由方法c.Router.PreHandle(request)c.Router.Handle(request)c.Router.PostHandle(request)}(&req)}}//启动连接,让当前连接开始工作func (c *Connection) Start() {//开启处理该链接读取到客户端数据之后的请求业务go c.StartReader()for {select {case <- c.ExitBuffChan://得到退出消息,不再阻塞return}}}//停止连接,结束当前连接状态Mfunc (c *Connection) Stop() {//1. 如果当前链接已经关闭if c.isClosed == true {return}c.isClosed = true//TODO Connection Stop() 如果用户注册了该链接的关闭回调业务,那么在此刻应该显示调用// 关闭socket链接c.Conn.Close()//通知从缓冲队列读数据的业务,该链接已经关闭c.ExitBuffChan <- true//关闭该链接全部管道close(c.ExitBuffChan)}//从当前连接获取原始的socket TCPConnfunc (c *Connection) GetTCPConnection() *net.TCPConn {return c.Conn}//获取当前连接IDfunc (c *Connection) GetConnID() uint32{return c.ConnID}//获取远程客户端地址信息func (c *Connection) RemoteAddr() net.Addr {return c.Conn.RemoteAddr()}
