写在前面的话
首先,我是一个golang语言的初学者, 这里纯粹是学习笔记,以便以后返回来查找,防止遗忘。文章内容来源于 刘丹兵老师的教程, 大家可以直接去看老师的视频来进行学习。
需求分析
搭建一个最基础的服务器框架,实现客户端向服务器发送一条数据,服务器将该数据返回到客户端
根据需求,对服务器进行如下的设计
编码实施
首先,先建立我们的目录结构
在自己golang环境的src目录下 新建文件下 zinx,这是我们游戏框架的名称(沿用了视频中的名称), 然后,在zinx目录下新建ziface目录和znet目录。在ziface目录下新建IServer.go文件,这里写我们的服务器接口。在znet目录下新建server.go文件,在这里写IServer接口的具体实现。
1.首先编写IServer.go 文件,设计接口
package ziface
//定义一个服务器接口
type IServer interface {
// 启动服务器
Start()
// 停止服务器
Stop()
// 运行服务器
Serve()
}
- 编写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)
}
}
接下来,分别启动服务端和客户端,得到以下结果
本章节结束,如果诸位觉得本文对您有所帮助,请点赞,谢谢
有疑问加站长微信联系(非本文作者)