Ainx框架实现 一

在这里插入图片描述

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。
📗本文收录于Ainx系列,大家有兴趣的可以看一看
📘相关专栏Rust初阶教程、go语言基础系列、spring教程等,大家有兴趣的可以看一看
📙Java并发编程系列,设计模式系列、go web开发框架 系列正在发展中,喜欢Java,GoLang,Rust,的朋友们可以关注一下哦!


📙 本文大部分都是借鉴刘丹冰大佬的zinx框架和文章,更推荐大家去读大佬的原文,本文只是个人学习的记录

@[TOC]

初识Ainx框架

在这里插入图片描述
上图就显示了所有的ainx框架的模块,我们后来将会一一实现。

Ainx-V0.1 代码实现

为了更好的看到Ainx框架,首先Ainx构建Ainx的最基本的两个模块ainterface和anet。
ainterface主要是存放一些Ainx框架的全部模块的抽象层接口类,Ainx框架的最基本的是服务类接口iserver,定义在aiface模块中。
anet模块是ainx框架中网络相关功能的实现,所有网络相关模块都会定义在anet模块中。

创建ainx框架

创建zinx文件夹,然后创建go项目

mkdir ainx
cd ./ainx
go mod init ainx

创建ainterface、anet模块

在ainx/下 创建ainterface、znet文件夹, 使当前的文件路径如下:
注意:下图由tree自动生成,要查看自己的目录也可以在命令行输入tree

└── ainx
    ├── ainterface
    │  
    └── anet

ainterface下创建服务模块抽象层iserver.go

首先我们给服务器模块抽象一个接口,因为它决定了我们整个框架入口的结构。

ainx/ainterface/iserver.go

package ainterface

//定义服务器接口
type IServer interface{
    //启动服务器方法
    Start()
    //停止服务器方法
    Stop()
    //开启业务服务方法
    Serve()
}

在anet下实现服务模块server.go

我们接下来实现我们的服务器的实体类,暂时我们给给它添加Name,IPVersion,IP,Port 四个属性,分别代表服务器的名字,服务器连接使用的ip协议,服务器绑定的IP和绑定的端口号。

ainx/anet>sever.go

package anet

import (
	"ainx/ainterface"
	"fmt"
	"net"
	"time"
)

type Server struct {
	// 设置服务器名称
	Name string
	// 设置网络协议版本
	IPVersion string
	// 设置服务器绑定IP
	IP string
	// 设置端口号
	Port string
}

//============== 实现 ainterface.IServer 里的全部接口方法 ========

// 开启网络服务
func (s *Server) Start() {
	fmt.Printf("[START] Server listenner at IP: %s, Port %s, is starting\n", s.IP, s.Port)

	// 开启一个go去做服务端的Listener业务
	go func() {
		// todo 未来目标是提供更多协议,可以利用if或者switch对IPVersion进行判断而选择采取哪种协议
		//1 获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, s.IP+":"+s.Port)
		if err != nil {
			fmt.Println("resolve tcp addr err: ", err)
			return
		}
		// 2 监听服务器地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}
		//	  已经成功监听
		fmt.Println("start Ainx server  ", s.Name, " success, now listenning...")
		//3 启动server网络连接业务
		for {
			//3.1 阻塞等待客户端建立连接请求
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err ", err)
				continue
			}
			//3.2 TODO Server.Start() 设置服务器最大连接控制,如果超过最大连接,那么则关闭此新的连接

			//3.3 TODO Server.Start() 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的

			//我们这里暂时做一个最大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 buf err ", err)
						continue
					}
				}
			}()
		}
	}()
}
func (s *Server) Stop() {
	fmt.Println("[STOP] Zinx server , name ", s.Name)
	//TODO  Server.Stop() 将其他需要清理的连接信息或者其他信息 也要一并停止或者清理
}
func (s *Server) Serve() {
	s.Start()
	//TODO Server.Serve() 是否在启动服务的时候 还要处理其他的事情呢 可以在这里添加
	//阻塞,否则主Go退出, listenner的go将会退出
	for {
		time.Sleep(10 * time.Second)
	}
}

/*
创建一个服务器句柄
*/
func NewServer(name string) ainterface.IServer {
	s := &Server{
		Name:      name,
		IPVersion: "tcp4",
		IP:        "0.0.0.0",
		Port:      "8080",
	}
	return s
}

好了,以上我们已经完成了Ainx-V0.1的基本雏形了,虽然只是一个基本的回写客户端数据,那么接下来我们就应该测试我们当前的Ainx-V0.1是否可以使用了。

Ainx框架单元测试样例

理论上我们应该可以现在导入zinx框架,然后写一个服务端程序,再写一个客户端程序进行测试,但是我们可以通过Go的单元Test功能,进行单元测试

创建ainx/znet/server_test.go

package anet

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

/*
模拟客户端
*/
func ClientTest() {
	fmt.Println("Client Test ... start")
	// 3秒之后发起调用,让服务端有时间启动
	time.Sleep(3 * time.Second)
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		fmt.Println("client start err,exit")
		return
	}
	for {
		_, err := conn.Write([]byte("hello word"))
		if err != nil {
			fmt.Println("client start err,exit")
			return
		}
		buf := make([]byte, 520)
		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], cnt)
		time.Sleep(1 * time.Second)

	}
}

// Server 模块测试函数
func TestServer(t *testing.T) {
	/*
		服务端测试
	*/
	//
	s := NewServer("first")
	go ClientTest()
	s.Serve()
}

之后便可以运行测试程序程序进行测试
测试结果

=== RUN   TestServer
[START] Server listenner at IP: 0.0.0.0, Port 8080, is starting
Client Test ... start
start Ainx server   first  success, now listenning...
Server call back : hello word,cnt =10 
 Server call back : hello word,cnt =10 
 Server call back : hello word,cnt =10 
 Server call back : hello word,cnt =10 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/370466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mysql+MybatisPlus+Vue实现基础增删改查CRUD

数据库 设计数据库 设计几个字段,主键id自动增长且不可为空 create table if not exists user (id bigint(20) primary key auto_increment comment 主键id,username varchar(255) not null comment 用户名,sex char(1) not null comment 性…

C++弹球游戏:Jump Ball Game

一、下载压缩包 请查看网站C弹球游戏:Jump Ball Game并且下载,可以看到如下界面: 二、匹配图标 把压缩包解压了: 右键点击Jump Ball Game.lnk,点击“属性”它将会是我们要运行的文件。 点击“更改图标”,选…

【HarmonyOS 4.0 应用开发实战】ArkTS 快速入门

个人名片: 🐼作者简介:一名大三在校生,喜欢AI编程🎋 🐻‍❄️个人主页🥇:落798. 🐼个人WeChat:hmmwx53 🕊️系列专栏:🖼️…

344. Reverse String(反转字符串)

题目描述 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 问题分析 以中间字符为轴,将两边的字符对换…

Python 轻量级定时任务调度:APScheduler

简述 APscheduler (Advanced Python Scheduler),作用为按指定的时间规则执行指定的作业。提供了基于日期date、固定时间间隔interval 、以及类似于Linux上的定时任务crontab类型的定时任务。该框架不仅可以添加、删除定时任务,还可以将任务存储到数据库…

浅谈Zookeeper及windows下详细安装步骤

1. Zookeeper介绍 1.1 分布式系统面临的问题 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统。 面临的问题:系统每个节点之间信息同步及共享 以一个小团队为例,面临的问题 通过网络进行信息…

蓝桥杯---生日蜡烛

某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛,现在算起来,他一共吹熄了236根蜡烛。请问,他从多少岁开始过生日party的? 请填写他开始过生日 party的年龄数。 注意:你提交的应该是一个整数,不要…

二分查找第二弹

目录 力扣852.山脉数组的峰顶索引 力扣162.寻找峰值 力扣153.寻找旋转排序数组中的最小值 力扣剑指Offer53.0-n-1缺失的数字 力扣852.山脉数组的峰顶索引 峰顶之前的全部比他小,峰顶之后的也比他小,把小于等于和大于分成两段 class Solution {publi…

TQ15EG开发板教程:使用vivado2023.1建立hello world工程

1:打开软件建立工程 2:使用vivado创建设计模块并生成bit文件 3:导出硬件平台,使用vitis建立工程 4:使用vitis创建应用程序项目 5:硬件设置与调试 1:打开软件建立工程 打开VIVADO2023.1 创建一个新的工程 输入项目名称和地址,下面那个选项为是否…

深入了解关联查询和子查询

推荐阅读 给软件行业带来了春天——揭秘Spring究竟是何方神圣(一) 给软件行业带来了春天——揭秘Spring究竟是何方神圣(二) 文章目录 推荐阅读关联查询子查询 关联查询 关联查询 从多张表中查询对应记录的信息,关联查…

网络原理-TCP/IP(5)

TCP协议 延迟应答 它也是基于滑动窗口,提高效率的一种机制,结合滑动窗口以及流量控制,能够以延迟应答ACK的方式,把反馈的窗口,搞大.核心在于允许范围内,让窗口尽可能大. 如果接收数据的主机立刻返回ACK应答,这时候返回的窗口可能比较小. 1.假设接收端缓冲区为1M.一次收到了5…

Java特别篇--关于线程创建的三种方式的总结对比

文章目录 一、常见3种创建线程的方式(1)方式1:继承Thread类的方式(2)方式2:实现Runnable接口的方式(3)方式3:通过Callable和Future接口创建线程 二、对比三种方式&#x…

CUDA/TensorRT部署知识点

CUDA相关: 1、CUDA核函数嵌套核函数的用法多吗? 答:这种用法非常少,主要是因为启动一个kernel本身就有一定延迟,会造成执行的不连续性。 2、如下代码里的 grid/block 对应硬件上的 SM 的关系是什么? 答:首先需要理解grid/block是软件层的概念,而SM是硬件层的概念。所…

python脚本将照片按时间线整理

说明:有一次自己瞎折腾,然后把服务器相册搞崩了,后来做了备份同步给找了回来,但是相册的时间线全乱了,看起来非常难受。所以就想通过文件夹的形式把照片重新分类,分类后的结构如下(红色字体为文件夹)&#…

人生百相,不过熵增熵减

这篇博文由两个问题衍生而来,分别是:“为什么除法比加法困难”、“什么是生命进化的目的”。在阅读其他人的解读时,发现都关联到了一个概念,熵。觉得十分有意思,因此记录一下自己的遐想。 熵(Entropy&#…

vulhub中spring的CVE-2022-22965漏洞复现

在JDK 9上运行的Spring MVC或Spring WebFlux应用程序可能存在通过数据绑定执行远程代码(RCE)的漏洞。 现在已知的利用方法要求应用程序以WAR部署的形式在Tomcat上运行,然而,该漏洞的性质更为普遍,可能有其他方法可以利…

docker安装-centos

Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10 卸载旧版本Docker sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine使用yum安装 yum 更新到最新版本: sudo yum update执行以下命令安装依赖包: sudo yum…

【无刷电机】无感方波驱动方案

无感方波驱动方案 1.通过无感过零信号构造霍尔换相信号2.无刷硬件驱动方案3.无感方波控制程序框架3.1有感方波控制3.2无感方波控制3.3无感启动方案3.4无感速度闭环控制1.通过无感过零信号构造霍尔换相信号 实现无感方波控制有软件比较和硬件比较两种方案。 软件比较是通过ADC采…

张维迎《博弈与社会》威胁与承诺(3)承诺行为

承诺的作用 上一节,我们探讨了如何在求解博弈时把不可置信的威胁或许诺排除出去,从而对参与人的行为做出合理的预测。如前所述,其中一个隐含的前提条件是,参与人要具有理性共识。而理性共识是一个要求很高的条件,现实生…

基于Springboot的校园失物招领网站(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的校园失物招领网站(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…