<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 2.Zinx-V0.2-簡單的連接封裝與業務綁定 V0.1版本我們已經實現了一個基礎的Server框架,現在我們需要對客戶端鏈接和不同的客戶端鏈接所處理的不同業務再做一層接口封裝,當然我們先是把架構搭建起來。 現在在`ziface`下創建一個屬于鏈接的接口文件`iconnection.go`,當然他的實現文件我們放在`znet`下的`connection.go`中。 #### 2.1 Zinx-V0.2代碼實現 ##### A\) ziface創建iconnection.go > zinx/ziface/iconnection.go ```go package ziface import "net" //定義連接接口 type IConnection interface { //啟動連接,讓當前連接開始工作 Start() //停止連接,結束當前連接狀態M Stop() //從當前連接獲取原始的socket TCPConn GetTCPConnection() *net.TCPConn //獲取當前連接ID GetConnID() uint32 //獲取遠程客戶端地址信息 RemoteAddr() net.Addr } //定義一個統一處理鏈接業務的接口 type HandFunc func(*net.TCPConn, []byte, int) error ``` 該接口的一些基礎方法,代碼注釋已經介紹的很清楚,這里先簡單說明一個HandFunc這個函數類型,這個是所有conn鏈接在處理業務的函數接口,第一參數是socket原生鏈接,第二個參數是客戶端請求的數據,第三個參數是客戶端請求的數據長度。這樣,如果我們想要指定一個conn的處理業務,只要定義一個HandFunc類型的函數,然后和該鏈接綁定就可以了。 ##### B\) znet 創建iconnection.go > zinx/znet/connection.go ```go package znet import ( "fmt" "net" "zinx/ziface" ) type Connection struct { //當前連接的socket TCP套接字 Conn *net.TCPConn //當前連接的ID 也可以稱作為SessionID,ID全局唯一 ConnID uint32 //當前連接的關閉狀態 isClosed bool //該連接的處理方法api handleAPI ziface.HandFunc //告知該鏈接已經退出/停止的channel ExitBuffChan chan bool } //創建連接的方法 func NewConntion(conn *net.TCPConn, connID uint32, callback_api ziface.HandFunc) *Connection{ c := &Connection{ Conn: conn, ConnID: connID, isClosed: false, handleAPI: callback_api, ExitBuffChan: make(chan bool, 1), } return c } /* 處理conn讀數據的Goroutine */ 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) cnt, err := c.Conn.Read(buf) if err != nil { fmt.Println("recv buf err ", err) c.ExitBuffChan <- true continue } //調用當前鏈接業務(這里執行的是當前conn的綁定的handle方法) if err := c.handleAPI(c.Conn, buf, cnt); err !=nil { fmt.Println("connID ", c.ConnID, " handle is error") c.ExitBuffChan <- true return } } } //啟動連接,讓當前連接開始工作 func (c *Connection) Start() { //開啟處理該鏈接讀取到客戶端數據之后的請求業務 go c.StartReader() for { select { case <- c.ExitBuffChan: //得到退出消息,不再阻塞 return } } } //停止連接,結束當前連接狀態M func (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 TCPConn func (c *Connection) GetTCPConnection() *net.TCPConn { return c.Conn } //獲取當前連接ID func (c *Connection) GetConnID() uint32{ return c.ConnID } //獲取遠程客戶端地址信息 func (c *Connection) RemoteAddr() net.Addr { return c.Conn.RemoteAddr() } ``` ##### C\) 重新更正一下Server.go中 處理conn的連接業務 zinx/znet/server.go ```go package znet import ( "errors" "fmt" "net" "time" "zinx/ziface" ) //iServer 接口實現,定義一個Server服務類 type Server struct { //服務器的名稱 Name string //tcp4 or other IPVersion string //服務綁定的IP地址 IP string //服務綁定的端口 Port int } //============== 定義當前客戶端鏈接的handle api =========== 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 } //============== 實現 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的Addr addr, 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 uint32 cid = 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, CallBackToClient) 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 NewServer (name string) ziface.IServer { s:= &Server { Name :name, IPVersion:"tcp4", IP:"0.0.0.0", Port:7777, } return s } ``` `CallBackToClient`是我們給當前客戶端conn對象綁定的handle方法,當然目前是server端強制綁定的回顯業務,我們之后會豐富框架,讓這個用戶可以讓用戶自定義指定handle。 在`start()`方法中,我們主要做了如下的修改: ```go //3.3 處理該新連接請求的 業務 方法, 此時應該有 handler 和 conn是綁定的 dealConn := NewConntion(conn, cid, CallBackToClient) cid ++ //3.4 啟動當前鏈接的處理業務 go dealConn.Start() ``` 好了,現在我們已經將connection的連接和handle綁定了,下面我們在測試一下Zinx-V0.2的框架是否可以使用吧。 #### 2.2 使用Zinx-V0.2完成應用程序 實際上,目前Zinx框架的對外接口并未改變,所以V0.1的測試依然有效。 Server.go ```go package main import ( "zinx/znet" ) //Server 模塊的測試函數 func main() { //1 創建一個server 句柄 s s := znet.NewServer("[zinx V0.1]") //2 開啟服務 s.Serve() } ``` 啟動Server.go ```bash go run Server.go ``` Client.go ```go package main import ( "fmt" "net" "time" ) func main() { fmt.Println("Client Test ... start") //3秒之后發起測試請求,給服務端開啟服務的機會 time.Sleep(3 * time.Second) conn,err := net.Dial("tcp", "127.0.0.1:7777") if err != nil { fmt.Println("client start err, exit!") return } for { _, err := conn.Write([]byte("hahaha")) if err !=nil { fmt.Println("write error 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) } } ``` 啟動Client.go進行測試 ```bash go run Client.go ``` 現在我們已經簡單初始了Zinx的雛形,但是目前離我們真正的框架還很遠,接下來我們來改進zinx框架。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看