c#软件开发学习笔记--TCP 粘包拆包、SqlSugar 框架

响应式编程(三)什么是粘包、拆包?如何解决? 阅读详情

学习总结:TCP 粘包拆包 与 SqlSugar 框架


一、TCP 粘包与拆包

1.1 问题背景

TCP 是面向字节流的协议,发送方写入的数据在接收方看来是一条连续不断的字节流,没有边界。因此会出现以下三种现象:

现象说明
粘包多次发送的消息被合并成一次接收(例如两条短消息挤在一个数据包中到达)
拆包一条消息被拆成多次接收(例如大消息被网络层切成多个数据包)
混合既有粘包又有拆包同时发生

注意:粘包拆包不是 TCP 的 Bug,而是字节流协议的固有特性。UDP 是面向报文的协议,不存在此问题。

1.2 常见解包方案

  1. 消息定长:每条消息固定长度,不足补齐。
  2. 特殊分隔符:例如以 \r\n 结尾(FTP、HTTP 头部采用此方式)。
  3. 头部长度字段(本案例采用):在消息体前加一个固定长度的头部,记录消息体的字节长度。

1.3 协议设计(本案例)

本案例采用 “4 字节头 + 变长消息体” 的方案:

+------------+-------------------+
|  Header    |     Body          |
|  4 bytes   |   N bytes         |
| (body长度) |  (UTF8 文本)       |
+------------+-------------------+
  • 头部:4 字节整数,存储消息体的字节长度
  • 字节序:网络字节序(大端),使用 IPAddress.HostToNetworkOrder / NetworkToHostOrder 转换
  • 消息体:UTF-8 编码的字符串

1.4 关键代码

1.4.1 编码:消息 → 字节流
/// <summary>
/// 将字符串编码为「4字节长度头 + 消息体」的字节包
/// </summary>
private byte[] EncodePackage(string msg)
{
    byte[] data = Encoding.UTF8.GetBytes(msg);
    // 将消息体长度转为网络字节序(大端),保证跨平台一致
    byte[] headLength = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(data.Length));
    byte[] package = new byte[4 + data.Length];
    Array.Copy(headLength, package, headLength.Length);      // 头部
    Array.Copy(data, 0, package, 4, data.Length);            // 消息体
    return package;
}
1.4.2 解码:从字节流中循环抽取完整包
/// <summary>
/// 从缓冲区 bsList 中循环解析出完整消息
/// 粘包:一次能解析出多条;拆包:长度不足时跳出等待下次数据
/// </summary>
private void TryParsePackage()
{
    while (bsList.Count >= 4)                         // 至少要有 4 字节头部
    {
        byte[] headBytes = bsList.GetRange(0, 4).ToArray();
        int bodyLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(headBytes, 0));
        int totalLength = 4 + bodyLength;

        if (bsList.Count < totalLength) break;        // 拆包:包不完整,等下一次

        byte[] bodyData = bsList.GetRange(4, bodyLength).ToArray();
        string msg = Encoding.UTF8.GetString(bodyData);
        AppendLog("收到消息:" + msg);

        bsList.RemoveRange(0, totalLength);           // 移除已解析部分,继续解析下一个
    }
}
1.4.3 接收数据 + 缓冲
/// <summary>
/// 异步循环读取网络流,累积到 bsList 后尝试解析
/// </summary>
private void ReceiveData(TcpClient client)
{
    cts = new CancellationTokenSource();
    Task.Run(async () =>
    {
        byte[] buffer = new byte[1024];
        while (!cts.IsCancellationRequested)
        {
            NetworkStream stream = client.GetStream();
            int len = await stream.ReadAsync(buffer, cts.Token);
            if (len == 0) { AppendLog("客户端断开连接"); break; }

            byte[] realData = new byte[len];
            Array.Copy(buffer, realData, len);
            bsList.AddRange(realData);                // 关键:累积到缓冲区

            TryParsePackage();
        }
    }, cts.Token);
}

1.5 流程示意

发送端:  msg ──EncodePackage──> [4字节头][body] ──> stream.Write

接收端:  stream.Read ──> bsList.AddRange ──> TryParsePackage (while循环)
                                                │
                                  ┌─────────────┴─────────────┐
                                  │ bsList.Count >= 4 ?        │
                                  │ 取出头部 → bodyLength       │
                                  │ 总长 4+bodyLength          │
                                  │ 不足 → break (拆包等待)     │
                                  │ 足够 → 取body → 处理 → 移除 │
                                  └───────────────────────────┘

1.6 要点小结

  • ✅ 用 List<byte> 作为接收缓冲区,累积所有到达字节
  • ✅ 用 while 循环解析,一次可拆出多个包(解决粘包)
  • ✅ 包不完整时 break 等待下次数据(解决拆包)
  • ✅ 头部使用网络字节序保证收发双方字节序一致
  • ✅ 解析完一个包后必须 RemoveRange 移除已处理部分

二、SqlSugar 第三方 ORM 框架

2.1 框架简介

SqlSugar 是一款老牌国产 .NET ORM 框架,由果糖大数据科技团队维护,开箱即用、易于上手。

2.2 两种使用模式

模式类特点
原生模式SqlSugarClient高性能,每次 new 新对象,禁止单例
单例模式SqlSugarScope对新手友好,解决大部分线程安全问题,必须单例

2.3 核心配置(本案例采用原生模式)

/// <summary>
/// 窗体加载时初始化 SqlSugarClient
/// </summary>
private void Form1_Load(object sender, EventArgs e)
{
    db = new SqlSugarClient(new ConnectionConfig()
    {
        ConnectionString = "server = localhost,64345; database = sugarDemo.db; uid = sa; pwd = 123123;Encrypt=True;TrustServerCertificate=True",
        DbType = DbType.SqlServer,
        IsAutoCloseConnection = true,           // 自动关闭连接,省去手动 using
    },
    db =>
    {
        // AOP:执行 SQL 时打印原生 SQL,方便调试
        db.Aop.OnLogExecuting = (sql, pars) =>
        {
            Console.WriteLine(UtilMethods.GetNativeSql(sql, pars));
        };
    });
}

2.4 实体定义

[SugarTable]                                              // 标记为数据库表
public class Student
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] // 主键 + 自增
    public int Id { get; set; }
    public string Name { get; set; }
    public int? Age { get; set; }                          // 可空类型对应数据库可空字段
}

2.5 数据库与表初始化

// 创建数据库(若不存在)
db.DbMaintenance.CreateDatabase();

// CodeFirst:根据实体类自动生成/同步表结构
db.CodeFirst.InitTables(typeof(Student));

2.6 核心 API(CRUD)

操作API示例
增db.Insertable<T>(entity).ExecuteCommand()db.Insertable(list).ExecuteCommand()
删db.Deleteable<T>(entity).ExecuteCommand()db.Deleteable<Student>(stu).ExecuteCommand()
改db.Updateable<T>(entity).ExecuteCommand()db.Updateable<Student>(stu).ExecuteCommand()
查db.Queryable<T>()...ToList()db.Queryable<Student>().Single(s => s.Id == id)
2.6.1 批量插入
List<Student> list = new List<Student>()
{
    new Student(){Name = "张三1", Age = 100},
    new Student(){Name = "张三2", Age = 200},
    new Student(){Name = "张三3", Age = 300},
};
int row = db.Insertable(list).ExecuteCommand();
2.6.2 条件查询 + 动态拼接

使用 Expressionable<T> 动态拼接 where 条件,避免写大量 if-else 分支 SQL。

/// <summary>
/// 根据界面输入条件动态拼接查询条件并分页绑定 DataGridView
/// </summary>
private void BindView()
{
    if (db == null) return;
    var express = Expressionable.Create<Student>();
    // AndIF:仅当条件成立时追加 AND 过滤
    express.AndIF(!string.IsNullOrWhiteSpace(textBox1.Text), s => s.Name.Contains(textBox1.Text));
    express.AndIF(!string.IsNullOrWhiteSpace(textBox2.Text), s => s.Age >= int.Parse(textBox2.Text));
    express.AndIF(!string.IsNullOrWhiteSpace(textBox3.Text), s => s.Age <= int.Parse(textBox3.Text));

    var list = db.Queryable<Student>()
                 .Where(express.ToExpression())
                 .ToPageList(pageNumber, pageSize, ref totalCount, ref totalPages)
                 .ToList();

    dataGridView1.DataSource = list;
    label2.Text = $"{pageNumber}/{totalPages}";
}
2.6.3 修改与删除(按主键定位)
// 修改:先查后改
int id = int.Parse(dataGridView1.SelectedRows[0].Cells["Id"].Value!.ToString()!);
Student stu = db.Queryable<Student>().Single(s => s.Id == id);
stu.Name = "三生三世";
stu.Age = 100;
db.Updateable<Student>(stu).ExecuteCommand();

// 删除
Student stu = db.Queryable<Student>().Single(s => s.Id == id);
db.Deleteable<Student>(stu).ExecuteCommand();

2.7 分页查询要点

  • ToPageList(pageNumber, pageSize, ref totalCount, ref totalPages) 一次返回当前页数据 + 总数 + 总页数
  • 翻页只需修改 pageNumber 后重新调用 BindView()
  • 每页条数变更时,应重置 pageNumber = 1,避免越界

2.8 要点小结

  • ✅ IsAutoCloseConnection = true 让连接管理自动化,避免资源泄漏
  • ✅ Aop.OnLogExecuting 是调试 SQL 的利器
  • ✅ Expressionable<T> 适合动态条件查询场景
  • ✅ CodeFirst.InitTables 实现"代码先行",实体变更直接同步表结构
  • ✅ CRUD 全部链式调用,统一以 ExecuteCommand()(增删改)或 ToList()/Single()(查)收尾

三、关联知识点

  • ADO.NET 五大对象:SqlConnection、SqlCommand、SqlDataAdapter、SqlDataReader、DataSet,SqlSugar 底层即基于此封装。
  • IOC / DI:SqlSugarClient 推荐使用 Scope 或瞬发注入,禁止单例。
  • 网络字节序:TCP 自定义协议应统一使用大端序(HostToNetworkOrder / NetworkToHostOrder)。

时序数据库TDengine安装及c#连接读写数据 物联网数据采集,需写入大量数据,这时就用到时序数据库来存储和快速读取我个人使用感觉国产的开源项目TDengine,比InfluxDB操作方便很多,容易上手,支持使用SqlSugar进行数据操作,跟操作mysql数据库一样的体验跟mysql最有特别之处,就是TDengine有个超级表=表结构模板 的概念,可以基于这个超级表的结构,建N个数量的子表,查询的时候,可以查单个子表,也可以查超级表所有子表的数据集合超级表概念如:建超级表A基于超级表A的结构 建子表 : A1、A2、A3、N。 阅读详情

相关推荐

C#上位机与西门子PLC全链路通信实战教程:数据采集+SQL存储+数据库报表查询+报警历史完整实现

在工业自动化领域,西门子PLC(S7-200Smart/1200/1500)凭借稳定的性能、强大的功能、完善的生态,稳居工业控制器的主流地位;而凭借开发效率高、界面美观、兼容性强、数据库操作便捷的优势,成为工业上位机开发的首选编程语言。二者的组合,是目前制造业、自动化产线、智能仓储、暖通自控等场景的绝对主流方案,也是工业上位机工程师必须吃透的核心技术栈。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1864

什么是粘包拆包

本文来说下什么是粘包拆包 文章目录概述 概述

wh柒八九的博客 5114

C# MES源码深度解析:技术选型、工单流转与落地实践

制造执行系统(MES)是连接计划层与车间现场的关键桥梁,专注于工单执行、设备数据采集与质量追溯。在.NET技术生态中,C#凭借高效的开发能力、成熟的设备通信协议支持(如OPC UA、Modbus)以及灵活的桌面端交互,成为中小型制造企业MES落地的主流选择。理解工单状态机设计、报工流程与批次追溯的数据模型,是评估一套MES源码质量的核心。通过合理的模块拆分与数据库设计,可以显著提升系统扩展性与稳定性。本文从技术选型、核心流程实现到部署二次开发踩坑,结合工程实践经验,为.NET开发者提供一套可直接参考的C#

weixin_34008784的博客 423

TCP的粘包拆包技术

TCP 是一个面向「流」的协议,所谓流就是没有界限的一长串二进制数据。在实际的传输过程中,TCP 会根据网络情况将数据包进行拆分或者拼装,如果业务没有定义一个明确的界限规则,在应用层的业务上就会出现粘包拆包的现象。 平时大家在网络编程过程中可能会遇到这样一种现象:客户端发送了一长串消息,服务端接受的消息揉在一起或者被拆分了,这样就会造成消息难以被正确理解。比如说有一天你特别想喝奶茶,看了一下外卖,「一点点」的奶茶看着不错,(一点点赶紧给我打钱 doge),于是你在群里发了一条消息,想找几个人拼奶茶: 一

Free雅轩的博客 3180

从原理到实践:手把手教你如何校准和使用六维力传感器(附常见问题排查)

本文详细解析六维力传感器的工作原理与校准方法,提供从选型到故障排查的完整指南。重点介绍电阻式与电容式技术对比、六步校准法实战以及温度补偿技巧,帮助工程师精准测量空间力场。适用于机器人触觉反馈、航空航天测试等高精度场景。

weixin_29309475的博客 388

UE5游戏逆向实战:用FModel提取.pak文件中的3D模型(附Dumper-7避坑指南)

本文详细介绍了如何使用FModel工具从UE5游戏的.pak文件中提取3D模型,并提供了Dumper-7的避坑指南。内容涵盖FModel工具链配置、UE5特有的unversioned properties问题解决方案、Dumper-7实战流程以及模型后处理技巧,帮助开发者高效获取游戏资产。

weixin_30872499的博客 422

聊聊TCP协议的粘包、拆包以及http是如何解决的?

TCP协议的粘包、拆包以及http是如何解决的

cj_eryue的博客 2万+

手把手教你用SNAP做全极化SAR图像分类

引言 最近在研究极化SAR图像分类方面的内容,发现用SNAP软件可以很方便的实现图像的分类。因为在入门过程中踩了很多坑,浪费了一些时间,为了不让大家踩坑,所以决定写下这篇教程。 前期准备 软件下载 SNAP是欧空局旗下的一个SAR图像处理软件,可以点击下载地址进行下载。 数据下载 数据下载地址:https://mdacorporation.com/sample_data/RS2_OK76385_...

zz651044657的博客 1万+

解决TCP粘包/拆包问题的方法及示例

还有一种解决TCP粘包/拆包问题的方法是使用定长协议,即规定每次发送的数据包都是固定长度,例如规定每次发送的数据包长度为固定的100个字节,如果发送的数据长度不足100字节,则在后面填充空格或者其他特定字符,如果超过100字节,则进行截断处理。由于网络的不可靠性,TCP为了提高传输效率,会将多个小数据块打包成一个大的数据块一起发送(称为TCP粘包),或者将一个大的数据块拆分成多个小的数据块发送(称为TCP拆包)。由于TCP是面向流的协议,发送的数据流会被自动分段,可能出现多个短消息被粘在一起发送的情况。

polsnet的专栏 4375

使用再生龙还原镜像文件到硬盘

1. 把制作好的再生龙光盘插入需要的电脑,开机按F4使用再生龙启动2. 选择默认的:Clonezailla live(Default settings,VGA 800*600),然后等待几分钟 3. 选择语言:简体中文 4. 选择不修改键盘映射 5. 选择使用再生龙          6. 选择硬盘/分区(存到/来自)镜像文件,此选项既可以制作镜像,也可以恢复镜像。 7. 使用本机的分区     ...

weixin_42168893的博客 1万+

达梦数据库与sharding-jdbc的深度适配实践

本文详细介绍了达梦数据库与sharding-jdbc的深度适配实践,包括驱动与依赖管理、核心适配实现、注册与配置等关键步骤。通过扩展shardingSphere的方式,成功实现了达梦数据库的分库分表功能,并提供了常见问题解决方案和性能优化建议,助力企业级应用高效处理海量数据。

weixin_30300225的博客 623

C#进阶-了解ORM框架SqlSugar并巧妙使用(附相关数据库工具)

通过NuGet包管理器搜索SqlSugar、MySql.Data、Newtonsoft.Json三个包并安装。

rwo_bear的博客 6389

[STM32F103C8T6]W5500+Modbus TCP(HAL库)

本章节是博主学习Modbus TCP所写的一篇文章Modbus TCP是Modbus的一个分支,主要用到网口通信的,在工业上也用的很频繁,我们公司最近的项目就是用的W5500+modbus TCP来和PC端的上位机通信和交互的。虽然这个项目不是我在写代码,但是我都学了Modbus RTU了,那我也抽空学习一下Modbus TCP吧。本次的Modbus TCP不是博主写的,是一个大佬开源的一个W5500写的一个Mobus TCP代码,我在这个基础上自己写了主机读从机多个数据,和主机写从机寄存器的函数。

sinat_58149788的博客 4086

c#软件开发学习笔记--WebAPI

Web API= Web Application Programming Interface(网络应用程序接口)。基于HTTP 协议的网络应用程序接口,使用JSON 或 XML格式传输数据。是服务器端应用程序,允许客户端通过 HTTP 请求访问服务器上的数据。支持RESTful 风格服务,是构建 RESTful 服务的理想选择。WebAPI 后台有一系列方法(接口),供其他项目类型使用。控制器是 WebAPI 定义接口的核心。本项目的核心控制器为。FromQuery与FromBody绑定方式。

Z599817841的博客 205

JSON 与 JSON-RPC 的区别

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,基于文本,采用人类可读的语法来表示结构化数据。它起源于JavaScript,但如今已被几乎所有主流编程语言支持。标准文档:RFC 4627数据类型:支持 String、Number、Boolean、Null、Object、Array 六种基本类型格式示例"name": "张三","age": 30,JSON-RPC(JSON Remote Procedure Call)是一种远程过程调用(RPC)协议。

h a 6 6 6 c k 为 你解决复杂难题! 146

基于STM32设计的掌上游戏机(运行NES游戏模拟器)详细开发过程

利用STM32单片机移植NES游戏模拟器,完成NES游戏开发,可以玩标准的NES游戏,已测试超级玛丽、魂斗罗之类的都可以正常运行。

4万+

TDengine超级表实战:用C#处理百万级传感器数据(附SqlSugar代码)

本文详细介绍了如何利用TDengine时序数据库的超级表功能,结合C#和SqlSugar ORM框架高效处理百万级传感器数据。内容涵盖从环境搭建、超级表设计,到使用C#实现高性能批量写入和复杂聚合查询的完整实战流程,为物联网数据存储与分析提供了可落地的解决方案。

weixin_29213655的博客 615

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

SqlSugar 处理 Oracle 闲置会话超时问题的最佳实践

在 Oracle 数据库应用开发中,你是否经常遇到这样的问题:应用程序运行一段时间后突然出现 `ORA-02396: exceeded maximum idle time` 错误?或者连接池中的连接因为长时间闲置而被数据库服务器主动断开,导致后续操作失败? Oracle 数据库默认会配置 `IDLE_TIME` 参数来限制会话的最大闲置时间,通常设置为 30 分钟到数小时不等。当连接超过这个时间...

gitblog_01411的博客 598

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

实战练习----模拟OPCUA通讯软件对PLC的地址进行监控

监控页面XAML代码,左侧是Treeview控件,可以去搜索一下这个怎么用的,监控区主要是用的datagrid来做的,要注意,由于数据类型为Bool的地址,他只有"True"和"False",那么我们的设定值肯定不能使用textbox,试想一下,你需要释放一个电机的使能,你居然要完整的输入"False"那简直也太坐牢了。主要实现的是把数据库中的内容按节点展开,我是通过"/"来表示的,比如"电机1参数/实际电压",那么实际电压就是电机1参数的叶子节点,那如果我的电机1参数下还有子节点呢?

qq_59495461的博客 1043

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

仓库温控系统技术笔记(WinForm + SQLSugar + N 层架构)

本文介绍了一个基于WinForm的仓库温控系统实现方案,采用N层架构设计。系统通过串口/TCP与温度传感器交互,使用SQLSugar ORM框架进行数据持久化,并利用GDI+绘制温度曲线。核心技术点包括:1)无边框窗体美化;2)五层架构解耦(UI/BLL/DAL/Model/Common);3)SQLSugar的高效数据访问;4)GDI+数据可视化;5)串口通讯设备交互。文章提供了完整的代码示例,重点说明了线程安全、资源释放等关键注意事项,为工业级温控系统开发提供了实用参考方案。

weixin_66547608的博客 1473

SqlSugar 存储过程读取实战:IsRefCursor 与 ParameterDirection 在 Oracle 下的配置验证

SqlSugar 调用 Oracle 存储过程返回空集,多半是游标参数没配对。本文用 IsRefCursor 与 ParameterDirection 三件套配置,配合实体映射与日志验证,一步排查读取为空问题。TaoToken 官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 提供辅助排错。

weixin_42599558的博客 4

C# 通用上位机追溯系统(WPF)——高效、稳定、可扩展的工业级解决方案

通用上位机追溯系统,使用wpf作为ui框架,应用程序使用.NetFramework 4.8框架。具备数据保存(数据库:MySql,ORM:Sqlsugar),与PLC交互(如:Fins,CipNet),Socket(如:Tcp,Udp,Modbus)、Com(RS232,RS485)通讯,与MES(如:Http请求、Web Api)交互功能。General.Device:存放通讯设备类,如:PLC、COM、SOCKET等;General.MES:存放MES交互类,如:Http请求调用Web Api接口;

weixin_38415306的博客 1148

避坑指南:Windows下TDengine3.0安装与C#连接那些坑(含端口配置陷阱)

本文详细解析了在Windows环境下部署TDengine 3.0时序数据库,并通过C#连接进行数据读写的完整流程与避坑指南。重点剖析了服务端配置、防火墙设置、端口连接等常见陷阱,并对比了使用SqlSugar ORM与原生驱动两种C#连接方案,为.NET开发者提供稳定高效的时序数据库集成实践。

xray4的博客 756

C#/Java 常用轮子 (子文章)(持续更新)

-----> 总文章 入口 C# 框架/类库名称介绍 Topshelf windows服务框架 Quartz 定时任务框架 NVelocity MVC视图引擎 NPOI 文档读写 SignalR WebSocket 框架 Swagger REST API 文档生成工具:NSwagSwa...

dibr63585的博客 523

Gear.NET:专为 .NET 工业自动化打造的微编排框架

工业软件不应是“低端”、“脏乱差”的代名词。Gear.NET 致力于将现代软件工程的优秀实践引入工业领域。如果你受够了那一堆难以维护的“屎山”代码,欢迎尝试 Gear.NET。让我们一起,把机器控制得优雅、精准、可靠。

tq6J5Yg14的博客 360

C#/.NET优秀项目和框架月度盘点:从桌面UI到工业通信与AI应用

在C#/.NET/.NET Core开发中,无论是桌面UI、Web后端还是上位机工业通信,开发者总在寻找“拿来即用”的解决方案。从Avalonia跨平台桌面框架、MAUI Hybrid模式,到FastEndpoints接口设计、EF Core与Dapper的选型,再到c#连接西门子opc、TcpListener多客户端并发、DirectShow摄像头采集等工控高频需求,以及Semantic Kernel为代表的LLM编排框架,每个方向都有值得关注的优秀项目。本文基于社区热议项目与高频搜索词,系统梳理了各技术

weixin_42530458的博客 128
上一篇: c#软件开发学习笔记--Modbus-TCP/UDP网口通讯
下一篇: c#软件开发学习笔记--WPF(控件、样式)
Z599817841
博客等级 码龄4年 12粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值