目录
- 前言
- 一、链接模块实现思路
- 二、模块结构
- 三、源码修改说明
- 四、完整源码
-
- 1 - iserver.go
- 2 - server.go
- 3 - iconnection.go
- 4 - connection.go
- 5 - 测试类server.go
- 6 - 测试类client.go
前言
- 之前的v0.1版本,已经实现了一个基础的Server框架,现在需要对客户端链接和不同的客户端链接锁处理的不同业务再做一层接口封装
- 在ziface下创建一个属于链接的接口文件iconnection.go,znet下创建文件connection.go实现链接接口
一、链接模块实现思路
二、模块结构
三、源码修改说明
- 1-新增iconnection链接接口:定义链接的方法
- 2-新增connection链接实现:实现链接
- 3-znet/server.go中start()方法的修改:将链接后的业务处理交给connection对象来处理
for {
conn, err := listenner.AcceptTCP()
if err != nil {
fmt.Println("Accept err", err)
continue
}
dealConn := NewConnection(conn, cid, CallBackToClient)
cid++
go dealConn.Start()
}
- 4-关于HandFunc的函数说明:
type HandleFunc func(*net.TCPConn, []byte, int) error
- 这个HandFunc是一个函数类型,是所有conn链接在处理业务的函数接口
- 第一个参数:socket原生链接
- 第二个参数:客户端请求的数据
- 第三个参数:客户端请求的数据长度
- 这样如果我们想要指定一个conn的处理业务,只需要定义一个HandFunc类型的函数,就可以和该链接绑定了
- 5-znet/server.go中新增CallBackToClient:是我们给当前客户端conn对象绑定的handle⽅法(目前这个handle是写死的,以后优化应该由用户自定义handle方法)
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
fmt.Println("[Conn Handle] CallbackToClient ...")
if _, err := conn.Write(data[:cnt]); err != nil {
fmt.Println("write back buf err", err)
return errors.New("CallBackToClient error")
}
return nil
}
四、完整源码
1 - iserver.go
package ziface
type IServer interface {
Start()
Stop()
Serve()
}
2 - server.go
package znet
import (
"errors"
"fmt"
"net"
"zinx/ziface"
)
type Server struct {
Name string
IPVersion string
IP string
Port int
}
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
fmt.Println("[Conn Handle] CallbackToClient ...")
if _, err := conn.Write(data[:cnt]); err != nil {
fmt.Println("write back buf err", err)
return errors.New("CallBackToClient error")
}
return nil
}
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, CallBackToClient)
cid++
go dealConn.Start()
}
}()
}
func (s *Server) Stop() {
}
func (s *Server) Serve() {
s.Start()
select {}
}
func NewServer(name string) ziface.IServer {
s := &Server{
Name: name,
IPVersion: "tcp4",
IP: "0.0.0.0",
Port: 8999,
}
return s
}
3 - iconnection.go
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
4 - connection.go
package znet
import (
"fmt"
"net"
"zinx/ziface"
)
type Connection struct {
Conn *net.TCPConn
ConnID uint32
isClosed bool
handleAPI ziface.HandleFunc
ExitChan chan bool
}
func NewConnection(conn *net.TCPConn, connID uint32, callback_api ziface.HandleFunc) *Connection {
c := &Connection{
Conn: conn,
ConnID: connID,
handleAPI: callback_api,
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)
cnt, err := c.Conn.Read(buf)
if err != nil {
fmt.Println("recv buf err", err)
continue
}
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()
}
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
}
5 - 测试类server.go
package main
import "zinx/znet"
func main() {
s := znet.NewServer("[zinx V0.2]")
s.Serve()
}
6 - 测试类client.go
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)
}
}