1.golang從零搭建游戲服務(wù)器框架 之 實(shí)現(xiàn)最簡(jiǎn)單的回顯服務(wù)器

寫在前面的話

首先,我是一個(gè)golang語(yǔ)言的初學(xué)者, 這里純粹是學(xué)習(xí)筆記,以便以后返回來(lái)查找,防止遺忘。文章內(nèi)容來(lái)源于 劉丹兵老師的教程, 大家可以直接去看老師的視頻來(lái)進(jìn)行學(xué)習(xí)。

需求分析

搭建一個(gè)最基礎(chǔ)的服務(wù)器框架,實(shí)現(xiàn)客戶端向服務(wù)器發(fā)送一條數(shù)據(jù),服務(wù)器將該數(shù)據(jù)返回到客戶端

根據(jù)需求,對(duì)服務(wù)器進(jìn)行如下的設(shè)計(jì)


圖片.png

編碼實(shí)施

首先,先建立我們的目錄結(jié)構(gòu)
在自己golang環(huán)境的src目錄下 新建文件下 zinx,這是我們游戲框架的名稱(沿用了視頻中的名稱), 然后,在zinx目錄下新建ziface目錄和znet目錄。在ziface目錄下新建IServer.go文件,這里寫我們的服務(wù)器接口。在znet目錄下新建server.go文件,在這里寫IServer接口的具體實(shí)現(xiàn)。

1.首先編寫IServer.go 文件,設(shè)計(jì)接口

package ziface

//定義一個(gè)服務(wù)器接口
type IServer interface {
    // 啟動(dòng)服務(wù)器
    Start()
    // 停止服務(wù)器
    Stop()
    // 運(yùn)行服務(wù)器
    Serve()
}
  1. 編寫server.go 文件,具體的實(shí)現(xiàn)啟動(dòng),停止,運(yùn)行服務(wù)器的方法

socket編程的通用步驟 獲取socket 對(duì)象->對(duì)ip地址進(jìn)行監(jiān)聽->阻塞等待客戶端連接->讀取客戶端傳過來(lái)的數(shù)據(jù)->業(yè)務(wù)處理
分析之后,我們必須縣對(duì)server對(duì)象進(jìn)行初始化,所以,在這里增加了一個(gè)初始化的方法

//初始化服務(wù)器的方法
func NewServer(name string) iface.IServer {
    s := &Server{
        Name:      name,
        IPVersion: "tcp4",
        IP:        "0.0.0.0",
        Port:      8999,
    }
    return s
}

啟動(dòng)服務(wù)器的實(shí)現(xiàn)

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

    go func() {
        // 獲取一個(gè)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
        }
        // 監(jiān)聽服務(wù)器的地質(zhì)
        listenner, err := net.ListenTCP(s.IPVersion, addr)
        if err != nil {
            fmt.Println("listen ", s.IPVersion, err)
            return
        }
        fmt.Println("start Zinx server succ,", s.Name, "succ, Listenning ..")
        // 阻塞等待客戶端連接
        // 處理客戶端連接業(yè)務(wù)
        for {
            // 如果有客戶端連接 返回
            conn, err := listenner.AcceptTCP()
            if err != nil {
                fmt.Println("Accept err :", err)
                return
            }

            // 客戶端已經(jīng)建立連接, 做一些業(yè)務(wù)處理
            // 做一個(gè)最大512字節(jié)的回顯業(yè)務(wù)
            go func() {
                for {
                    buf := make([]byte, 512)
                    cnt, err := conn.Read(buf)
                    if err != nil {
                        fmt.Println("recv buf err :", err)
                        continue
                    }
                    if _, err := conn.Write(buf[:cnt]); err != nil {
                        fmt.Println("write back bur err", err)
                        continue
                    }
                }
            }()
        }
    }()
}

server.go 的完整代碼

package znet

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

//iServer 接口的實(shí)現(xiàn) 定義一個(gè)Server的服務(wù)器模塊
type Server struct {
    // 服務(wù)器的名稱
    Name string
    //  服務(wù)器版本
    IPVersion string
    //服務(wù)器監(jiān)聽的ip
    IP string
    //服務(wù)器監(jiān)聽的端口
    Port int
}

//啟動(dòng)服務(wù)器
func (s *Server) Start() {
    fmt.Printf("[Start] Server Listenner at IP :%s, Port %d, is starting \n", s.IP, s.Port)

    go func() {
        // 獲取一個(gè)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
        }
        // 監(jiān)聽服務(wù)器的地質(zhì)
        listenner, err := net.ListenTCP(s.IPVersion, addr)
        if err != nil {
            fmt.Println("listen ", s.IPVersion, err)
            return
        }
        fmt.Println("start Zinx server succ,", s.Name, "succ, Listenning ..")
        // 阻塞等待客戶端連接
        // 處理客戶端連接業(yè)務(wù)
        for {
            // 如果有客戶端連接 返回
            conn, err := listenner.AcceptTCP()
            if err != nil {
                fmt.Println("Accept err :", err)
                return
            }

            // 客戶端已經(jīng)建立連接, 做一些業(yè)務(wù)處理
            // 做一個(gè)最大512字節(jié)的回顯業(yè)務(wù)
            go func() {
                for {
                    buf := make([]byte, 512)
                    cnt, err := conn.Read(buf)
                    if err != nil {
                        fmt.Println("recv buf err :", err)
                        continue
                    }
                    if _, err := conn.Write(buf[:cnt]); err != nil {
                        fmt.Println("write back bur err", err)
                        continue
                    }
                }
            }()
        }
    }()
}

//停止服務(wù)器
func (s *Server) Stop() {
    // 將服務(wù)器開辟的資源,連接停止 釋放
}

//運(yùn)行服務(wù)器
func (s *Server) Serve() {
    s.Start()

    //TODO  做啟動(dòng)服務(wù)后的額外業(yè)務(wù)
    // 阻塞狀態(tài)
    select {}
}

//初始化服務(wù)器的方法
func NewServer(name string) ziface.IServer {
    s := &Server{
        Name:      name,
        IPVersion: "tcp4",
        IP:        "0.0.0.0",
        Port:      8999,
    }
    return s
}

到此為止,我們的最見但的服務(wù)器就已經(jīng)搭建好了,為了測(cè)試我們的服務(wù)器,我們來(lái)測(cè)試以下
首先來(lái)寫我們的服務(wù)端程序,新建項(xiàng)目目錄 demo
server.go

package main

import "zinx/znet"

func main() {
    // 創(chuàng)建一個(gè)server 句柄
    s := znet.NewServer("server")
    // 啟動(dòng)server
    s.Serve()
}

client.go

package main

import (
    "fmt"
    "net"
    "time"
)

func main() {
    fmt.Println("Client start")
    time.Sleep(1 * time.Second)
    // 連接遠(yuǎn)程服務(wù)器 得到conn
    conn, err := net.Dial("tcp", "127.0.0.1:8999")
    if err != nil {
        fmt.Println("client start err, exit")
        return
    }

    // 調(diào)用Write方法寫入數(shù)據(jù)
    for {
        _, err := conn.Write([]byte("hello"))
        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 err", err)
            return
        }
        fmt.Printf("server call back:%s,cnt=%d \n", buf, cnt)
        time.Sleep(1 * time.Second)

    }
}

接下來(lái),分別啟動(dòng)服務(wù)端和客戶端,得到以下結(jié)果

圖片.png

本章節(jié)結(jié)束,如果諸位覺得本文對(duì)您有所幫助,請(qǐng)點(diǎn)贊,謝謝

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容