Ainx-V0.2-简单的连接封装与业务绑定

Go 语言数据库事务详解:从 db.Begin 到 Tx 的正确用法 本文详解Go语言中database/sql事务的正确用法,从*sql.Tx的底层模型出发,阐述事务与连接池的关系,提供标准事务模板,并强调使用db.BeginTx控制隔离级别与超时。重点剖析常见陷阱:误用db而非tx执行SQL、defer顺序错误、忽略Commit错误、事务过长导致资源耗尽等。结合可运行示例,涵盖事务内查询、预处理语句及保存点模拟嵌套事务,全面覆盖工程实践中的关键细节。 阅读详情
在这里插入图片描述

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


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

Ainx-V0.2-简单的连接封装与业务绑定

V0.1版本我们已经实现了了⼀一个基础的Server框架,现在我们需要对客户端链接和不不同的客户端链接所处 理理的不不同业务再做⼀一层接⼝口封装,当然我们先是把架构搭建起来。
现在在 ainterface 下创建⼀一个属于链接的接⼝⽂文件 iconnection.go ,当然他的实现⽂文件我们放在 anet 下的 connection.go 中。

aiface创建iconnection.go

ainx/ainterface/iconnection.go

package ainterface

import "net"

type IConnection interface {
	// 启动连接,让当前连接开始工作
	Start()
	// 停止链接,结束当前连接状态
	Stop()
	//从当前连接获取原始的socket TCPConn GetTCPConnection() *net.TCPConn //获取当前连接ID
	GetConnID() uint32 //获取远程客户端地址信息 RemoteAddr() net.Addr
}

// 定义⼀一个统⼀一处理理链接业务的接⼝口
type HandFunc func(*net.TCPConn, []byte, int) error

该接⼝的⼀些基础方法,代码注释已经介绍的很清楚,这里先简单说明⼀个HandFunc这个函数类型, 这个是所有conn链接在处理业务的函数接⼝,第⼀参数是socket原⽣链接,第二个参数是客户端请求的数据,第三个参数是客户端请求的数据长度。这样,如果我们想要指定⼀一个conn的处理业务,只要定义一个HandFunc类型的函数,然后和该链接绑定就可以了了。

anet 创建iconnection.go

ainx/anet/connection.go

package anet

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

type Connection struct {
	//当前链接的socket TCP套接字
	Conn *net.TCPConn
	// 当前链接的ID也可以称作SessionID,ID全局唯一
	ConnID uint32
	// 当前链接的关闭状态
	isClosed bool
	// 处理该链接方法的API
	handleAPI ainterface.HandFunc
	// 告知该链接已经退出/停止的channel
	ExitBuffChan chan bool
}

// 创建链接的方法
func NewConnection(conn *net.TCPConn, connID uint32, callback_api ainterface.HandFunc) *Connection {
	c := &Connection{
		Conn:         conn,
		ConnID:       connID,
		isClosed:     false,
		handleAPI:    callback_api,
		ExitBuffChan: make(chan bool, 1),
	}
	return c
}

// 处理conn读数据的Goroutine
func (c *Connection) StartReader() {
	fmt.Println("Reader Goroutine is running")
	defer fmt.Println(c.RemoteAddr().String(), "conn reader exit!")
	defer c.Stop()
	for {
		buf := make([]byte, 512)
		cnt, err := c.Conn.Read(buf)
		// 读取数据失败,退出连接
		if err != nil {
			fmt.Println("recv buf err ", err)
			c.ExitBuffChan <- true
			continue
		}
		// 调用当前业务链(这里执行的是当前conn的绑定的handle方法)
		if err := c.handleAPI(c.Conn, buf, cnt); err != nil {
			fmt.Println("connID ", c.ConnID, "handle is err")
			c.ExitBuffChan <- true
			return
		}

	}
}

// 启动连接,让当前链接工作
func (c *Connection) Start() {
	// 开启处理该链接读取到客户端数据之后的请求业务
	go c.StartReader()
	for {
		select {
		case <-c.ExitBuffChan:
			// 得到退出消息,不再阻塞
			return
		}
	}
}

// 停止链接,结束当前链接状态M
func (c *Connection) Stop() {
	//1.如果当前链接关闭
	if c.isClosed == true {
		return
	}
	c.isClosed = true
	//TODO Connection Stop() 如果用户注册了该链接的关闭回调业务,那么在此刻应该显示调用

	// 关闭socket链接
	err := c.Conn.Close()
	if err != nil {
		return
	}

	//通知从缓冲队列读数据的业务,该链接已经关闭
	c.ExitBuffChan <- true

	//关闭该链接全部管道
	close(c.ExitBuffChan)
}

// 从当前链接获取原始的socket TCPConn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

// 获取当前链接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

// 获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

重新更更正⼀一下Server.go中 处理理conn的连接业务

ainx/anet/server.go

package anet

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

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

// ============== 定义当前客户端链接的handle api ===========
func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	//回显业务
	fmt.Println("[Conn Handle] CallBackToClient ...")
	if _, err := conn.Write(data[:cnt]); err != nil {
		fmt.Println("write back buf err", err)
		return errors.New("CallBackToClient error")
	}
	return nil
}

// ============== 实现 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业务
	// todo 未来目标是提供更多协议,可以利用if或者switch对IPVersion进行判断而选择采取哪种协议,下面整个方法要重写
	go func() {
		//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...")

		//TODO server.go 应该有一个自动生成ID的方法
		var cid uint32
		cid = 0
		//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 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的
			dealConn := NewConnection(conn, cid, CallBackToClient)
			cid++

			//3.4 启动当前链接的处理业务
			go dealConn.Start()
		}
	}()
}
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
}

CallBackToClient 是我们给当前客户端conn对象绑定的handle⽅方法,当然⽬目前是server端强制绑定 的回显业务,我们之后会丰富框架,让这个⽤用户可以让⽤用户⾃自定义指定handle。
在 start() ⽅方法中,我们主要做了了如下的修改:

	//3.3 处理该新连接请求的 业务 方法, 此时应该有 handler 和 conn是绑定的
	dealConn := NewConntion(conn, cid, CallBackToClient)
	cid +
	//3.4 启动当前链接的处理业务
	go dealConn.Start()

实际上,⽬目前Zinx框架的对外接⼝口并未改变,所以V0.1的测试依然有效。我们依然可以启动V0.1的测试类经行测试,测试结果如下

=== 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...
Reader Goroutine is running
[Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
 [Conn Handle] CallBackToClient ...
Server call back : hello word,cnt =10 
从零开始学习 Go 1.25 编程 今天是你新生活的第一天,无论年龄、背景如何,改变从这一刻开始。CodeGym帮助成千上万普通人转型为程序员,从零基础到掌握Go语言,完成真实项目,甚至入职心仪岗位。Go语言简洁高效,适合服务器端开发,是云基础设施、微服务和高负载系统的首选。2026年正是入行良机,你的经验反而是优势。别犹豫,迈出第一步,你将收获技能、自信与全新人生。🚀 阅读详情

相关推荐

ABAP代码检查(Code Review)

1、SLIN 扩展程序检查 也可通过(SE38工具栏->检查-扩展程序检查) 进入 2、ATC 检查 通过<SE38菜单栏-检查-ABAP测试主控室> 或事物代码SCI, 支持自定义检查变式 SCI可以配置检查变式满足特殊需求,配置对象集用于批量检查 3、通过ABAP测试主控室实现统一管理,定期检查作业和监控功能(事务代码ATC) 参考 SLIN...

u012232542的博客 6072

【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c

AI 编程时代,开发语言选型需综合考量AI适配度、编译速度、跨平台与学习成本。Python以海量语料和即时执行成首选,适用于AI/ML与原型开发;TypeScript凭借类型系统与秒级构建,成为前端及应用层主流;Go以极速编译与统一风格,契合AI代理高效迭代需求。Rust/C++虽性能强,但编译慢、学习成本高,不适于快速试错。综合推荐:优先选Python、TypeScript、Go,兼顾效率与生态,实现最优AI协作体验。

freewebsys的专栏 626

(R,线性回归)R语言里的模型诊断图(Residuals vs Fitted,Normal QQ , Scale-Location ,Residuals Leverage)

线性回归,是概率统计学里最重要的统计方法,也是机器学习中一类非常重要的算法。线性模型简单理解非常容易,但是内涵是非常深奥的。尤其是线性回归模型中的Diagnostics plot的阅读与理解一直被认为是线性回归中的一个难点。 在任何线性模型中,能够直接“lm”(模型有意义),既要考虑各个参数的t-test所得出的p-value,也要考虑总体模型F-检验得出的p-value。在这之后,还要清楚一个...

qq_35837578的博客 7万+

每天10分钟学Go:第5课 switch分支判断

本课程讲解 Go 语言 switch 分支判断核心用法,涵盖单值匹配、多 case 合并、无表达式条件分支、fallthrough 穿透与类型 switch 断言,搭配可运行代码示例,带你掌握 Go 分支结构语法与实战写法。

2501_94567985的博客 259

DeepSeek 框架和技术栈分析

DeepSeek 诞生于对更高效、更强大的深度学习计算和模型训练的追求。随着深度学习模型的规模不断增大,如大型语言模型(LLMs)和复杂的视觉模型,传统的框架在处理这些大规模模型时面临着性能瓶颈和资源利用效率低下的问题。DeepSeek 旨在解决这些问题,通过优化框架设计和采用先进的技术栈,实现更高效的模型训练和推理,同时降低计算成本。

yournameplease的专栏 1512

美亚杯取证比赛必备:Veracrypt挂载+检材解压保姆级教程(附常见错误排查)

本文提供美亚杯数字取证竞赛的Veracrypt挂载与检材解压保姆级教程。详细解析从分卷压缩包解压(密码格式为MeiyaCup+年份)到使用Veracrypt正确挂载加密容器的全流程,并附有常见错误排查与高级应急方案,帮助选手高效突破技术门槛,顺利进入取证分析阶段。

alice7model的博客 1060

TinyGo 驱动 ESP32 端侧 AI 推理实战:纯 Go 实现轻量机器学习模型部署全流程

基于乐鑫官方 TinyGo 教程,从零实现纯 Go 语言开发 ESP32 端侧 AI 推理应用,覆盖环境搭建、模型转换到全流程部署。

嵌入式扫地僧 517

广东电信兆能Z82盒子救砖记:手把手教你用U盘强刷HI3798MV100固件(附短接图)

本文详细介绍了广东电信兆能Z82盒子变砖后的救砖方法,重点讲解了使用U盘强刷HI3798MV100固件的全流程,包括诊断、准备工作、短接操作及刷机后的优化设置。特别针对m8233主板和8188无线方案的机型,提供了实用的短接图和操作技巧,帮助用户成功恢复设备。

weixin_30325487的博客 405

每天10分钟学Go:第9课 Range循环

在 Go 里,`range` 常用来遍历切片、数组、字符串、映射和通道。它会在每次循环时,把当前元素的信息交给循环变量。前面《》我们已经会写普通的for循环,可以把range理解成一种更方便的遍历方式。

2501_94567985的博客 129

OpenClaw Manager Pro - 可视化管理工具

OpenClaw Manager Pro 是一个现代化的 Web 管理界面,用于管理多个 OpenClaw Gateway 实例。🎨美观的界面:深色主题,渐变设计,现代化 UI📡实时监控:WebSocket 实时推送状态和日志🔧完整管理:创建、编辑、删除、启动、停止 Gateway📊多渠道支持:飞书、Telegram、Discord、Slack、微信、钉钉🧩技能管理:可视化配置 61+ 个技能🌍跨平台:支持 macOS、Linux、Windows使用自定义模型系统会自动在中创建},

Maynor的博客 3087

基于深度学习的异常检测实战:从自编码器到GAN

本文通过一个完整的实战案例,展示了如何使用自编码器和GAN进行异常检测。我们详细介绍了数据准备、模型定义、训练和评估的步骤,并提供了可运行的代码。希望本文能为读者在实际项目中应用异常检测技术提供实用的指导和启发。

Programming Talk 243

2026-11-11-Go分布式锁实战

线上偶发重复扣库存,查了半天是业务执行超过了锁的过期时间,锁提前释放,另一个请求拿到锁又执行了一遍。单机锁在多实例部署下失效,Redis SET NX PX 加锁、Lua 脚本原子释放、看门狗续期,这篇讲透分布式锁三大坑,附实现对照表和实战清单。

利威尔的博客,主要分享一些go后端,agent相关知识,都是最新最前沿而且是免费的,在我的专栏里有各种方向的详细分类和内容整理,详细内容请阅读主页置顶文章,希望对你有帮助。 296

激光除草技术原理与应用全解析

激光除草技术通过光热、光化学等效应精准破坏杂草组织,核心参数包括功率(20-6000W)、波长(400nm-10.6μm)和脉冲宽度。主要应用于大田作物(如玉米、棉花)、经济作物(烟草、果树)及城市绿化,具有环保(无化学污染)、高效(识别率≥95%)和非接触等优势,但存在设备成本高(20-50万元)、技术门槛高等局限。当前技术融合AI识别、多光谱协同等创新,国产设备如华工智耘已实现95.3%识别精度。虽短期投入较高,但长期可降低30%除草成本,并带来环境效益(每亩减排1.2吨CO₂)

start_up_go的博客 558

每天10分钟学Go:第1课 环境搭建与第一个Go程序

本号专注分享实战干货、避坑指南、性能调优、面试重难点, 每一篇都是亲手落地测试,帮你少走弯路、快速提升核心竞争力。5、将go程序构建成可执行的二进制文件:go build hello-world.go。3、编辑go文件写入程序:vim hello-world.go。4、运行go程序:go run hello-world.go。2、创建go文件:touch hello-world.go。1、创建项目目录:mkdir go-test261111。2、配置go环境变量。

2501_94567985的博客 119

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Go 泛型入门:类型参数、约束与 Map/Filter/Stack

掌握类型参数、约束、~ 与 union,写出通用 Map/Filter/Stack,并知道什么时候不该用泛型。

JudithHuang的博客 216

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Go 测试实战:表驱动、Benchmark 与 httptest

从表驱动、子测试到 Benchmark/Fuzz/httptest,建立“测行为不测实现”的测试习惯。

JudithHuang的博客 200

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

day01-认识Go语言 + golang环境的安装

Go语言由Google开发,2009年发布,兼具编译型性能与脚本语言易用性。其优势包括运行快、语法简洁、跨平台构建、丰富标准库及原生并发支持(goroutine与channel),适用于微服务、区块链等场景。安装时需配置GOROOT(安装路径)、GOPATH(工作空间,含pkg和bin目录)及GOBIN,并将%GOROOT%\bin、%GOBIN%、%GOPATH%加入系统Path。通过命令行验证环境后,可使用GoLand等IDE进行开发,快速上手高效编程。

2301_77190282的博客 230

Go CPU 剖析的“地基“:信号、CAS、写屏障、无锁环形缓冲

本文通过“卡点自查表”梳理Go CPU剖析(cpuprof.go)中反直觉设计的底层逻辑,聚焦信号处理、CAS自旋锁、写屏障与无锁缓冲四大核心机制。指出所有设计皆源于信号处理器“不可阻塞、不碰堆、不持锁”的铁律,进而推导出:CompareAndSwap一次即走、环形缓冲无锁写入、预分配内存等策略的本质是向“在任意指令间被中断”这一事实妥协。结合多核并发与操作系统调度原理,揭示了高性能采样器如何在极端约束下实现低延迟、高吞吐。

不愿言弃-念何的博客 636

Go1.25 升级后 GoLand 调试提示【变量不可用】解决方案

顶部菜单Help→在弹出的配置文件中添加下面一行,路径替换为你本机 dlv.exe 真实路径Windows 路径使用正斜杠,不要用反斜杠保存配置文件,完全重启 GoLand(不是只重启调试会话)Go 大版本升级后,优先检查 Delve 兼容性,这是 Go1.24+、Go1.25 最常见的调试踩坑点。升级dlv + 指定dlv路径 + 关闭编译优化参数,90% 的“变量不可用”问题都可以解决。

关于代码的那些事 235

Go FX 依赖注入框架:从入门到实战

FX 的核心思想就是“声明式依赖管理”—— 你只需要告诉它"我有这些组件,它们需要什么",剩下的创建、排序、生命周期都由框架自动处理。特性传统方式FX 方式依赖顺序手动维护自动解析生命周期手写 start/stopfx.Hook 自动调度测试难度高(需真实依赖)低(接口易 mock)代码可读性分散在各处集中在 module 中错误提示运行时 panic启动时清晰报错对于中大型 Go 项目,FX 能显著降低代码耦合度,提升可测试性和可维护性。

ggaofengg的专栏 173

Go 定时任务实战:工业边缘场景下的 robfig/cron

工业边缘网关里有大量周期性工作:设备状态轮询、数据同步、定时上报、日志清理。,本文从角度梳理其用法、任务封装、并发控制与常见的坑。

ZenovaEdgeOS的博客 456

纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS

moejs 是一个纯 Go 编写的高性能 JavaScript 运行时,专为 Go 程序中的插件沙箱场景设计。发布于 2026 年 11 月,由 new-api 维护者 Calcium-Ion 开发,相较 C 版 QuickJS 快 35%,内存占用仅 81 KiB,单次调用仅 6.9 微秒。支持快速复用运行时、零拷贝解析、安全沙箱与 TypeScript 直接编译,通过 test262 80971 个用例零失败。适合高并发插件系统,如 AI 网关钩子处理,已在实际场景中实现请求吞吐量提升 8.6 倍。仓库

前端之虎陈随易 253

Tailscale 上手:把几台机器拼成一个局域网

一台每天背来背去的笔记本,一台家里的 Windows 台式,一台常年开着的 Linux 小主机,外加一台云上的 VPS。于是每次想在笔记本上连一次小主机,流程都是:回忆 IP → 发现变了 → 去路由器后台查 → 发现不在同一个网 → 打开某个穿透工具 → 折腾十分钟 → 干正事只要两分钟。Tailscale 解决的就是这一串前置动作。装完之后,上面这些机器在我眼里变成了四个稳定的名字,不管它们实际待在世界哪个网络里。

weixin_42357472的博客 222

运行go web服务,检测mysql服务和端口

如果你的窗口里显示的是别的报错文字(比如 ‘xxx’ 不是内部或外部命令、系统找不到指定的路径、或 Go 编译报错),把那几行原文发我,我再精确修——不过现在这版 bat 已经把最常见的三个坑(数据库、端口、闪退看不到错误)都堵上了。启动 MySQL:用干净的 my.ini 直接起 mysqld.exe(绕开 phpstudy 面板配置),验证连通:oa_admin_rule 554 行、oa_admin 2 行,数据完好。服务本身还能起来,但登录、菜单全依赖数据库,所以你看到的是红色警告 + 登录失效。

xinhuanjieyi的博客 202

每天10分钟学Go:第8课 映射(Map)

本文搭配可运行的完整示例代码,系统讲解 Go 语言 Map 的创建、增删改查、遍历等核心语法,整理了 maps 标准库用法与 8 个高频踩坑点,帮你快速掌握 Go 哈希表的正确使用方式。

2501_94567985的博客 219

rofbuf.go —— 单写单读无锁环形缓冲

该文详解 Go 运行时 profBuf 的无锁环形缓冲设计,解决信号处理器(无 g、不可分配)与用户 goroutine 间安全通信难题。通过原子操作、2的幂环长、打包索引(64位分三段)、溢出记录合并及 ABA 防护机制,实现高并发下低延迟、零锁的数据传递。核心创新在于计数运算三件套与溢出协议,确保在极端环境下仍能可靠捕获 CPU profile 事件。

不愿言弃-念何的博客 575
上一篇: 小程序 常用组件
下一篇: go安装与设置
过去日记
过去日记 新星创作者: 后端开发技术领域 新星创作者: 后端开发技术领域
博客等级 码龄3年 5343粉丝 225原创
评论 33
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

过去日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值