Zinx框架学习 - 构建最基础的Server

2023-11-09

Zinx - V0.1 构建最基础的Server

Zinx的框架结构:

整体思路:

客户端发送请求到服务器端,服务端会有一个Goroutine专门处理listenner和监听这个过程,然后有客户端连接过来之后会启动一个客户端处理Goroutine,这个Goroutine会分别开启一个客户端读写Goroutine,Reader是用来从客户端把数据读到已经开辟好的工作池中,工作池处理业务会针对用户自已经注册好的自定义好的业务来取一些业务规则来去处理数据,当数据处理完之后会将数据再交给Write Handler回写给客户端

Zinx 的最基本的两个模块ziface和zent:

  • ziface主要是存放一些Zinx框架的全部模块的抽象层接口类

Zinx 框架的最基本的服务类接口iserver,定义在该模块中

  • znet模块是Zinx框架中网络相关功能的实现,所有网络相关模块定义在这里

基础的Server模块拥有的三个方法和相应属性

代码实现

在iserver.go中定义一个服务器接口,提供三个方法

package ziface

//定义一个服务器接口
type IServer interface {
	//启动服务器
	Start()
	//停止服务器
	Stop()
	//运行服务器
	Serve()
}

然后再server.go中将该接口实例化,定义一个Server结构体对象,继承服务器接口即实现接口中的方法

实现接口中的方法前我们需要提供一个初始化Server对象的方法NewServer(),该方法返回的是一个抽象层iserver,在该方法中创建一个server对象并将其返回

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

首先实现Serve方法,在其中一定会调用Start方法将其服务器启动,所以先要实现Start方法,开发一个单体服务器有以下三个步骤

  • 获取一个TCP的Addr,即创建一个套接字
  • 监听服务器的地址
  • 监听成功后阻塞的等待客户端链接,处理客户端链接业务(读写)

其中第三步中我们使用for循环不断遍历等待listenner.AcceptTCP()的返回,如果没有客户端连接就会一直阻塞,如果有连接过来就会返回一个conn句柄和客户端进行基本的读写操作

已经有客户端建立连接后,我们就可以起一个协程去承载一些业务,在这里做一个最基本的最大512字节长度的显业务,在这个协程中不断地从客户端获取数据,所以也要用一个for循环

// 1 获取一个TCP的Addr
addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
if err != nil {
	fmt.Println("resolve tcp addt error : ", 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 succ, ", s.Name, " succ, Listenning...")

//3 阻塞的等待客户端链接,处理客户端链接业务(读写)
for {
	//如果有客户端链接过来,阻塞会返回
	conn, err := listenner.AcceptTCP()
	if err != nil {
		fmt.Println("Accept err", err)
		continue
	}

	//已经与客户端建立间接,做一些业务, 做一个最基本的最大512字节长度的回显业务
	go func() {
		for {
			buf := make([]byte, 512)
			cnt, err := conn.Read(buf)
			if err != nil {
				fmt.Println("recv buf err ", err)
				continue
			}

			fmt.Printf("recv client buf %s, cnt %d\n", buf, cnt)
			//回显功能
			if _, err := conn.Write(buf[:cnt]); err != nil {
				fmt.Println("write back buf err ", err)
				continue
			}
		}
	}()
}

但如果这样写,这个等待客户端连接listenner.AcceptTCP()的过程会阻塞,所以我们可以将整个Start业务用go func()来承载

然后再回到Serve()方法中,因为Start()本身是异步的,如果不在Serve()方法中进行阻塞,主线程在调用Start()后就会结束,服务器就没了,所以我们需要select阻塞

//运行服务器
func (s *Server) Serve() {
	//启动server的服务功能
	s.Start()

	//TODO 做一些启动服务器之后的额外业务

	//阻塞状态
	select {}
}

server.go完整代码

package znet

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

//iServer的接口实现,定义一个Server的服务器模块
type Server struct {
	//服务器的名称
	Name string
	//服务器绑定的ip版本
	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() {
		// 1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.IP, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addt error : ", 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 succ, ", s.Name, " succ, Listenning...")

		//3 阻塞的等待客户端链接,处理客户端链接业务(读写)
		for {
			//如果有客户端链接过来,阻塞会返回
			conn, err := listenner.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}

			//已经与客户端建立间接,做一些业务, 做一个最基本的最大512字节长度的回显业务
			go func() {
				for {
					buf := make([]byte, 512)
					cnt, err := conn.Read(buf)
					if err != nil {
						fmt.Println("recv buf err ", err)
						continue
					}

					fmt.Printf("recv client buf %s, cnt %d\n", buf, cnt)
					//回显功能
					if _, err := conn.Write(buf[:cnt]); err != nil {
						fmt.Println("write back buf err ", err)
						continue
					}
				}
			}()
		}
	}()
}

//停止服务器
func (s *Server) Stop() {
	//TODO 将一些服务器的资源、状态或者一些已经开辟的链接信息 进行停止或者回收
}

//运行服务器
func (s *Server) Serve() {
	//启动server的服务功能
	s.Start()

	//TODO 做一些启动服务器之后的额外业务

	//阻塞状态
	select {}
}

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

服务端测试

为了我们这个框架能够边写边使用,我们创建一个myDemo模块来测试Zinx框架,其中创建一个Server.go文件,该文件是基于Zinx框架开发的服务器端应用程序,在main函数中创建一个server句柄,使用Zinx的api,然后启动server

package main

import "zinx/znet"

//基于Zinx框架来开发的 服务器端应用程序
func main() {
	//1 创建一个server句柄,使用Zinx的api
	s := znet.NewServer("[zinx V0.1]")
	//2 启动server
	s.Serve()
}

客户端测试

  • 直接链接远程服务器,得到一个conn链接
  • 链接调用Write 写数据(for循环不断写),(服务器有将字符串返回的功能)

需要注意的是,我们要在客户端的for循环中将cpu阻塞,否则会将cpu性能跑满

package main

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

//模拟客户端
func main() {
	fmt.Println("client start...")

	time.Sleep(1 * time.Second)

	//1 直接链接远程服务器,得到一个conn链接
	conn, err := net.Dial("tcp", "127.0.0.1:8999")
	if err != nil {
		fmt.Println("client start err, exit!")
		return
	}

	for {
		//2 链接调用Write 写数据
		_, err := conn.Write([]byte("Hello Zinx V0.1.."))
		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 error")
			return
		}

		fmt.Printf(" server call back: %s, cnt = %d\n", buf, cnt)

		//cpu阻塞
		time.Sleep(1 * time.Second)
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Zinx框架学习 - 构建最基础的Server 的相关文章

随机推荐

  • 自然语言处理实验—分词算法(含python代码及详细例子讲解)

    自然语言处理实验 分词算法 最近在学自然语言处理 这是第一个上机实验自然语言处理的分词算法 也是自然语言处理比较入门的算法 和大家分享一下 首先 自然语言处理 英文是 Nature Language Process 简称 NLP 是人工智能
  • 【PHP教程(二)】php登陆验证(附代码)

    1 登陆脚本 2 受保护的网页示例 3 注销脚本 4 注意事项 5 Hash函数字符串转换 6 php登陆脚本 哈希值验证 可以使用 PHP 创建登录脚本 PHP 提供了用于处理用户身份验证和会话的内置函数和功能 这是登录系统的基本组件 这
  • 2023春节祝福系列第一弹(上)(放飞祈福孔明灯,祝福大家身体健康)(附完整源代码及资源免费下载)

    2023春节祝福系列第一弹 上 放飞祈福孔明灯 祝福大家身体健康 附完整源代码及资源免费下载 目录 一 前言 二 一片星光闪烁的旋转星空 1 效果展示 2 相关源代码 3 语法解释 3 1 线性渐变 linear gradient 3 2
  • Java异常知识点总结

    Java异常知识点总结 1 异常处理机制主要回答了三个问题 What Where Why What 异常类型回答了什么被抛出 Where 异常堆栈跟踪回答了在哪抛出 Why 异常信息回答了为什么被抛出 2 Java异常体系 RuntimeE
  • Python的Object基类__repr__方法

    Python的Object基类 repr 方法 Python基类的內建方法 repr 是执行一个官方的 或者正式的 代表一个对象的字符串 也就是说可以将字符串转换成一个Python对象 如果可能的话 最好是有效的表达式字符串 如果不可能的话
  • Visual Studio 2017 如何更改缓存以及组件的路径,以保证VS2017正常启动

    当安装完Visual Studio 2017时 发现安装过程中设置的缓存路径或组件存放路径不合理 但一旦修改 会导致Visual Studio 2017出现项目加载失败等问题 修改方法是通过 regedit命令打开windows注册表 然后
  • 财务系统软件c语言,用vc++6.0编写一个简单的财务应用程序来计算职工所得的实际工资...

    满意答案 xfitijnf 2014 09 30 采纳率 51 等级 12 已帮助 32118人 又写了一个简单的 c语言 另外 我和一楼不是一个人 123456789101112131415161718192021222324252627
  • Redis为服务器设置密码

    以下以Windows版本为例 在 redis windows service conf 文件 设置 requirepass foobared requirepass 123456 masterauth
  • AD常用使用快捷键和技巧

    PCB布线常使用 ctrl m 测量长度 ctrl C 取消显示测量长度 Q 单位切换 shift ctrl r 取消显示标注 shift S 显示层切换 ctrl 右击 高亮显示一条线 ctrl D PCB 2D显示设置 层 透明度 A
  • OpenCV:imwrite函数保存图片

    imwrite函数功能 用于将图像保存到指定的文件 可以为各种格式的图像 函数原型 bool cv imwrite const String filename InputArray img const std vector
  • js实现input的赋值

    input框赋值 如下所示 是一个文本框的html代码 实际开发中 要涉及到将数据库中的数据取出然后放入input框中
  • UML 用例图、顺序图、状态图、类图、包图、协作图、流程图

    面向对象的问题的处理的关键是建模问题 建模可以把在复杂世界的许多重要的细节给抽象出 许多建模工具封装了UML 也就是Unified Modeling Language 这篇课程的目的是展示出UML的精彩之处 UML中有九种建模的图标 即 用
  • vue事件对象、冒泡、阻止默认行为

    事件对象
  • 【满分】【华为OD机试真题2023 JAVA&JS】任务混部

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 任务混部 知识点差分 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 公司创新实验室正在研究如何最小化资源成本 最大化资源利用率 请你设计算法帮他们解决一个任务混
  • sql-labs注入1-10关

    sql labs注入第1 10关 Less 1 输入 id 1登录页面正常 Order by对前面的数据进行排序 这里有三列数据 我们就只能用order by 3 超过3就会报错 order by 4 的结果显示结果超出 爆数据库名 id
  • SpringBoot+MyBatis搭建迷你小程序

    本项目如下 maven的安装目录在哪 setting文件放在哪 仓库在哪 分别为G Program Files x86 apache maven 3 5 4 conf 与G Program Files x86 apache maven 3
  • 【高等代数】行列式的定义和性质

    文章目录 逆序数 逆序数的定义 逆序数的一个重要性质 行列式的定义 行列式的性质 逆序数 逆序数的定义 一个排列中的某两个数字 如果前面的数大于后面的数 那么它们就是一个逆序 一个排列中逆序的总数就称为这个排列的逆序数 逆序数用 j 1
  • JAVA的安装与卸载

    1 java的卸载 1 删除java的安装目录 2 删除系统环境变量里的JAVA HOME和Path里面的bin目录和jre bin目录 3 cmd输入java version 查看是否删除取消 2 java的安装 1 百度搜索jdk1 8
  • 【算法题】螺旋矩阵III (求解n阶蛇形矩阵)

    一 问题的提出 n阶蛇形矩阵的特点是按照图1所示的方式排列元素 n阶蛇形矩阵是指矩阵的大小为n n 其中n为正整数 题目背景 一个 n 行 n 列的螺旋矩阵可由如图1所示的方法生成 观察图片 找出填数规律 填数规则为从 1 开始填到 n n
  • Zinx框架学习 - 构建最基础的Server

    Zinx V0 1 构建最基础的Server Zinx的框架结构 整体思路 客户端发送请求到服务器端 服务端会有一个Goroutine专门处理listenner和监听这个过程 然后有客户端连接过来之后会启动一个客户端处理Goroutine