1.golang从零搭建游戏服务器框架 之 实现最简单的回显服务器

孟安乐Aaron · · 2162 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

写在前面的话

首先,我是一个golang语言的初学者, 这里纯粹是学习笔记,以便以后返回来查找,防止遗忘。文章内容来源于 刘丹兵老师的教程, 大家可以直接去看老师的视频来进行学习。

需求分析

搭建一个最基础的服务器框架,实现客户端向服务器发送一条数据,服务器将该数据返回到客户端

根据需求,对服务器进行如下的设计


图片.png

编码实施

首先,先建立我们的目录结构
在自己golang环境的src目录下 新建文件下 zinx,这是我们游戏框架的名称(沿用了视频中的名称), 然后,在zinx目录下新建ziface目录和znet目录。在ziface目录下新建IServer.go文件,这里写我们的服务器接口。在znet目录下新建server.go文件,在这里写IServer接口的具体实现。

1.首先编写IServer.go 文件,设计接口

package ziface

//定义一个服务器接口
type IServer interface {
    // 启动服务器
    Start()
    // 停止服务器
    Stop()
    // 运行服务器
    Serve()
}
  1. 编写server.go 文件,具体的实现启动,停止,运行服务器的方法

socket编程的通用步骤 获取socket 对象->对ip地址进行监听->阻塞等待客户端连接->读取客户端传过来的数据->业务处理
分析之后,我们必须县对server对象进行初始化,所以,在这里增加了一个初始化的方法

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

启动服务器的实现

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

    go func() {
        // 获取一个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
        }
        // 监听服务器的地质
        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 ..")
        // 阻塞等待客户端连接
        // 处理客户端连接业务
        for {
            // 如果有客户端连接 返回
            conn, err := listenner.AcceptTCP()
            if err != nil {
                fmt.Println("Accept err :", err)
                return
            }

            // 客户端已经建立连接, 做一些业务处理
            // 做一个最大512字节的回显业务
            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 接口的实现 定义一个Server的服务器模块
type Server struct {
    // 服务器的名称
    Name string
    //  服务器版本
    IPVersion string
    //服务器监听的ip
    IP string
    //服务器监听的端口
    Port int
}

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

    go func() {
        // 获取一个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
        }
        // 监听服务器的地质
        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 ..")
        // 阻塞等待客户端连接
        // 处理客户端连接业务
        for {
            // 如果有客户端连接 返回
            conn, err := listenner.AcceptTCP()
            if err != nil {
                fmt.Println("Accept err :", err)
                return
            }

            // 客户端已经建立连接, 做一些业务处理
            // 做一个最大512字节的回显业务
            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
                    }
                }
            }()
        }
    }()
}

//停止服务器
func (s *Server) Stop() {
    // 将服务器开辟的资源,连接停止 释放
}

//运行服务器
func (s *Server) Serve() {
    s.Start()

    //TODO  做启动服务后的额外业务
    // 阻塞状态
    select {}
}

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

到此为止,我们的最见但的服务器就已经搭建好了,为了测试我们的服务器,我们来测试以下
首先来写我们的服务端程序,新建项目目录 demo
server.go

package main

import "zinx/znet"

func main() {
    // 创建一个server 句柄
    s := znet.NewServer("server")
    // 启动server
    s.Serve()
}

client.go

package main

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

func main() {
    fmt.Println("Client start")
    time.Sleep(1 * time.Second)
    // 连接远程服务器 得到conn
    conn, err := net.Dial("tcp", "127.0.0.1:8999")
    if err != nil {
        fmt.Println("client start err, exit")
        return
    }

    // 调用Write方法写入数据
    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)

    }
}

接下来,分别启动服务端和客户端,得到以下结果

图片.png

本章节结束,如果诸位觉得本文对您有所帮助,请点赞,谢谢


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:孟安乐Aaron

查看原文:1.golang从零搭建游戏服务器框架 之 实现最简单的回显服务器

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2162 次点击  
加入收藏 微博
下一篇:Golang应用领域
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传