寫在前面的話
首先,我是一個(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ì)

編碼實(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()
}
- 編寫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é)果

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