go 模拟TCP粘包和拆包,及解决方法
1. 什么是 TCP 粘包与拆包?
- 粘包(Sticky Packet)
粘包是指在发送多个小的数据包时,接收端会将这些数据包合并成一个数据包接收。由于 TCP 是面向流的协议,它并不会在每次数据发送时附加边界信息。所以当多个数据包按顺序发送时,接收端可能会一次性接收多个数据包的数据,造成数据被粘在一起。
粘包一般发生在发送端每次写入的数据 < 接收端套接字(Socket)缓冲区的大小。
假设发送端发送了两个消息:消息1:“Hello”,消息2:“World”;由于 TCP 是流协议,接收端可能会接收到如下数据:“HelloWorld”。这种情况就是粘包,接收端就无法准确区分这两个消息。
- 拆包(Packet Fragmentation)
拆包是指发送的数据包在传输过程中被分割成多个小包。尽管发送端可能发送了一个完整的消息,但由于 TCP 协议在网络传输时可能会对数据进行分段,接收端可能接收到的是多个小数据包。
拆包一般发生在发送端每次写入的数据 > 接收端套接字(Socket)缓冲区的大小。
假设发送端发送了一个大的消息:“Hello, this is a long message.”;但是在传输过程中,网络层可能会将该消息拆分成多个小包,接收端可能先收到一部分数据:“Hello, this”,然后再收到另外一部分:“is a long message.”;这样接收端就会得到多个数据包,且它们并不代表单一的逻辑消息。
2. go 模拟TCP粘包
- server.go(接收端)
package mainimport ("bufio""fmt""io""net"
)func handleConnection(conn net.Conn) {defer conn.Close()// 创建缓冲读取器,读取客户端数据reader := bufio.NewReader(conn)var buffer [1024]bytefor {// 持续读取数据n, err := reader.Read(buffer[:])if err == io.EOF {break}if err != nil {fmt.Println("Error reading data:", err)break}recvStr := string(buffer[:n])// 打印接收到的数据fmt.Println("Received:", recvStr)}
}func main() {// 启动服务器,监听 8080 端口ln, err := net.Listen("tcp", ":8080")if err != nil {fmt.Println("Error starting server:", err)return}defer ln.Close()fmt.Println("Server started on port 8080...")for {// 等待客户端连接conn, err := ln.Accept()if err != nil {fmt.Println("Error accepting connection:", err)continue}// 处理连接go handleConnection(conn)}
}
- client.go(发送端)
package mainimport ("fmt""net""time"
)func main() {// 连接到服务器conn, err := net.Dial("tcp", "localhost:8080")if err != nil {fmt.Println("Error connecting to server:", err)return}defer conn.Close()// 模拟粘包和拆包for i := 0; i < 100; i++ {// 发送粘包情况:多个小消息一次发送message := fmt.Sprintf("Message %d\n", i+1)conn.Write([]byte(message))}// 等待服务器输出接收到的消息time.Sleep(2 * time.Second)
}
- 执行结果分析
可以看到接收端收到的消息并非都是一条,说明发生了粘包
3. go模拟TCP拆包
- server.go(接收端)
package mainimport ("bufio""fmt""io""net"
)func handleConnection(conn net.Conn) {defer conn.Close()// 创建缓冲读取器,读取客户端数据reader := bufio.NewReader(conn)var buffer [18]bytefor {// 持续读取数据n, err := reader.Read(buffer[:])if err == io.EOF {break}if err != nil {fmt.Println("Error reading data:", err)break}recvStr := string(buffer[:n])// 打印接收到的数据fmt.Println("Received message :", recvStr)}
}func main() {// 启动服务器,监听 8080 端口ln, err := net.Listen("tcp", ":8080")if err != nil {fmt.Println("Error starting server:", err)return}defer ln.Close()fmt.Println("Server started on port 8080...")for {// 等待客户端连接conn, err := ln.Accept()if err != nil {fmt.Println("Error accepting connection:", err)continue}// 处理连接go handleConnection(conn)}
}
- client.go(发送端)
package mainimport ("fmt""net""strings""time"
)func main() {// 连接到服务器conn, err := net.Dial("tcp", "localhost:8080")if err != nil {fmt.Println("Error connecting to server:", err)return}defer conn.Close()// 构造一个超过默认 MTU 的大数据包(32 字节)message := strings.Repeat("A", 32)// 模拟发送大量数据for i := 0; i < 100; i++ {fmt.Printf("Sending message : %s\n", message)conn.Write([]byte(message))}// 等待服务器输出time.Sleep(2 * time.Second)
}
- 执行结果分析
可以看到接收端对接收到的数据进行了拆分,说明发生了拆包
4. 如何解决 TCP 粘包与拆包问题?
4.1 自定义协议
发送端将请求的数据封装为两部分:消息头(发送数据大小)+消息体(发送具体数据);接收端根据消息头的值读取相应长度的消息体数据
- server.go(接收端)
服务端接收到数据时,首先读取前4个字节来获取消息的长度,然后再根据该长度读取完整的消息体
package mainimport ("encoding/binary""fmt""io""log""net"
)// readMessage 函数根据长度字段读取消息
func readMessage(conn net.Conn) (string, error) {// 读取4个字节的长度字段lenBytes := make([]byte, 4)_, err := io.ReadFull(conn, lenBytes)if err != nil {return "", fmt.Errorf("failed to read length field: %v", err)}// 解析消息长度msgLength := binary.BigEndian.Uint32(lenBytes)// 读取消息体msgBytes := make([]byte, msgLength)_, err = io.ReadFull(conn, msgBytes)if err != nil {return "", fmt.Errorf("failed to read message body: %v", err)}return string(msgBytes), nil
}func handleConnection(conn net.Conn) {defer conn.Close()// 一直循环接收客户端发来的消息for {msg, err := readMessage(conn)if err != nil {log.Printf("Error reading message: %v", err)break}fmt.Println("Received message:", msg)}
}func main() {// 启动监听服务listener, err := net.Listen("tcp", ":8080")if err != nil {log.Fatalf("Error starting server: %v", err)}defer listener.Close()fmt.Println("Server is listening on port 8080...")// 接受客户端连接并处理for {conn, err := listener.Accept()if err != nil {log.Printf("Error accepting connection: %v", err)continue}// 启动新的 Goroutine 处理客户端请求go handleConnection(conn)}
}
- client.go(发送端)
客户端将连接到服务端,并发送多个消息。每个消息的前4字节表示消息的长度,随后是消息体
package mainimport ("bytes""encoding/binary""log""net"
)// sendMessage 函数将消息和长度一起发送给服务端
func sendMessage(conn net.Conn, msg string) {// 计算消息的长度msgLen := uint32(len(msg))buf := new(bytes.Buffer)// 将消息长度转换为4字节的二进制数据binary.Write(buf, binary.BigEndian, msgLen)// 将消息体内容添加到缓冲区buf.Write([]byte(msg))// 发送缓冲区数据到服务端conn.Write(buf.Bytes())
}func main() {// 连接到服务端conn, err := net.Dial("tcp", "127.0.0.1:8080")if err != nil {log.Fatalf("Error connecting to server: %v", err)}defer conn.Close()// 发送多个消息sendMessage(conn, "Hello, Server!")sendMessage(conn, "This is a second message.")sendMessage(conn, "Goodbye!")
}
4.2 固定长度数据包
每个消息的长度是固定的(例如 1024 字节)。如果客户端发送的数据长度不足指定长度,则会使用空格填充,确保每个数据包的大小一致
- server.go(接收端)
服务端接收到的数据是固定长度的。每次接收 1024 字节的数据,并将其打印出来。如果数据不足 1024 字节,服务端会读取并处理这些数据。
package mainimport ("fmt""io""log""net""strings"
)// handleConnection 函数处理每个客户端的连接
func handleConnection(conn net.Conn) {defer conn.Close()// 设定每个消息的固定长度const messageLength = 1024buf := make([]byte, messageLength)for {// 每次读取固定长度的消息_, err := io.ReadFull(conn, buf)if err != nil {if err.Error() == "EOF" {// 客户端关闭连接break}log.Printf("Error reading message: %v", err)break}// 将读取的字节转换为字符串并打印msg := string(buf)// 去除空格填充fmt.Println("Received message:", strings.TrimSpace(msg))}
}func main() {// 启动 TCP 监听listener, err := net.Listen("tcp", ":8080")if err != nil {log.Fatalf("Error starting server: %v", err)}defer listener.Close()fmt.Println("Server is listening on port 8080...")// 等待客户端连接for {conn, err := listener.Accept()if err != nil {log.Printf("Error accepting connection: %v", err)continue}// 启动新的 Goroutine 处理每个客户端的连接go handleConnection(conn)}
}
- client.go(发送端)
客户端会向服务器发送固定长度的消息,如果消息长度不足 1024 字节,则会填充空格
package mainimport ("log""net""strings"
)// sendFixedLengthMessage 函数向服务端发送固定长度的消息
func sendFixedLengthMessage(conn net.Conn, msg string) {// 确保消息长度为 1024 字节,不足部分用空格填充if len(msg) < 1024 {msg = msg + strings.Repeat(" ", 1024-len(msg))}// 发送消息到服务端_, err := conn.Write([]byte(msg))if err != nil {log.Fatalf("Error sending message: %v", err)}
}func main() {// 连接到服务端conn, err := net.Dial("tcp", "127.0.0.1:8080")if err != nil {log.Fatalf("Error connecting to server: %v", err)}defer conn.Close()// 发送固定长度的消息sendFixedLengthMessage(conn, "Hello, Server!")sendFixedLengthMessage(conn, "This is a second message.")sendFixedLengthMessage(conn, "Goodbye!")
}
4.3 特殊字符来标识消息边界
通过在发送端每条消息的末尾加上 \n,然后接收端使用 ReadLine() 方法按行读取数据来区分每个数据包的边界
- server.go(接收端)
服务端会监听端口,并按行读取客户端发送的消息。每个消息的末尾会有一个 \n 来标识消息的结束
package mainimport ("bufio""fmt""log""net""strings"
)func handleConnection(conn net.Conn) {defer conn.Close()// 创建一个带缓冲的读取器reader := bufio.NewReader(conn)for {// 读取客户端发送的一行数据,直到遇到 '\n' 为止line, err := reader.ReadString('\n')if err != nil {log.Printf("Error reading from client: %v", err)break}// 去掉结尾的换行符line = strings.TrimSpace(line)fmt.Printf("Received message: %s\n", line)}
}func main() {// 启动 TCP 监听listener, err := net.Listen("tcp", ":8080")if err != nil {log.Fatalf("Error starting server: %v", err)}defer listener.Close()fmt.Println("Server is listening on port 8080...")// 等待客户端连接for {conn, err := listener.Accept()if err != nil {log.Printf("Error accepting connection: %v", err)continue}// 启动新的 Goroutine 处理每个客户端的连接go handleConnection(conn)}
}
- client.go(发送端)
客户端向服务端发送消息,每条消息末尾都会加上一个 \n,然后发送到服务器
package mainimport ("log""net"
)func sendMessage(conn net.Conn, message string) {// 将消息添加换行符并发送message = message + "\n"_, err := conn.Write([]byte(message))if err != nil {log.Fatalf("Error sending message: %v", err)}
}func main() {// 连接到服务端conn, err := net.Dial("tcp", "127.0.0.1:8080")if err != nil {log.Fatalf("Error connecting to server: %v", err)}defer conn.Close()// 发送几条消息sendMessage(conn, "Hello, Server!")sendMessage(conn, "How are you?")sendMessage(conn, "Goodbye!")
}
5. 三种方式的优缺点对比
特性 | 固定长度方式 | 特殊字符分隔方式 | 自定义协议方式 |
---|---|---|---|
实现简单 | 高 | 中 | 低 |
带宽效率 | 低(需要填充) | 高(仅传输有效数据) | 高(仅传输有效数据,且灵活处理) |
灵活性 | 低 | 中 | 高 |
易于调试 | 高(每包大小固定) | 中(需解析换行符等) | 低(需要解析协议头和体) |
性能开销 | 低 | 低 | 中等(需要额外解析消息头) |
适用场景 | 长度固定的消息 | 消息大小可变但有清晰的分隔符 | 复杂协议、支持多类型消息的场景 |
相关文章:
go 模拟TCP粘包和拆包,及解决方法
1. 什么是 TCP 粘包与拆包? 粘包(Sticky Packet) 粘包是指在发送多个小的数据包时,接收端会将这些数据包合并成一个数据包接收。由于 TCP 是面向流的协议,它并不会在每次数据发送时附加边界信息。所以当多个数据包按顺…...
论文笔记PhotoReg: Photometrically Registering 3D Gaussian Splatting Models
1.abstract 最近推出的3D高斯飞溅(3DGS),它用多达数百万个原始椭球体来描述场景,可以实时渲染。3DGS迅速声名鹊起。然而,一个关键的悬而未决的问题仍然存在:我们如何将多个3DG融合到一个连贯的模型中?解决这个问题将使…...
宝塔服务器安装备份配置
1.服务器下载安装宝塔功能 if [ -f /usr/bin/curl ];then curl -sSO https://download.bt.cn/install/install_panel.sh;else wget -O install_panel.sh https://download.bt.cn/install/install_panel.sh;fi;bash install_panel.sh ed8484bec执行后选择y 等待下载完成会给出…...
ubuntu22 安装CUDA
在Ubuntu系统中,使用nvidia-smi命令可以看到当前GPU信息,在右上角可以看到CUDA Version,意思是最大支持的CUDA版本号。 安装下载 CUDA Toolkit 11.6 Downloads | NVIDIA Developer https://developer.nvidia.com/cuda-downloads?target_osL…...
LabVIEW故障诊断中的无故障数据怎么办
在使用LabVIEW进行故障诊断时,可能会面临“无故障数据”的情况。这种情况下,缺乏明确的故障参考,使得系统难以通过传统对比法进行故障识别。本文将介绍应对无故障数据的关键策略,包括数据模拟、特征提取和基于机器学习的方法&…...
开发模式选择与最佳实践指南20241230
开发模式选择与最佳实践指南 引言 在现代软件开发中,选择合适的开发模式直接影响项目的开发效率和质量。本文将帮助您: 🎯 了解三种主流开发模式的优缺点💡 根据项目特点选择最适合的开发模式🔧 掌握混合开发模式的…...
超详细!一文搞定PID!嵌入式STM32-PID位置环和速度环
本文目录 一、知识点1. PID是什么?2. 积分限幅--用于限制无限累加的积分项3. 输出值限幅--用于任何pid的输出4. PID工程 二、各类PID1. 位置式PID(用于位置环)(1)公式(2)代码使用代码 2. 增量式…...
Redhat7 PCS建立无共享存储浮动地址集群
更新记录 日期版本号内容9/22/2024Ver 1.0重新排版修正 0写在前面 0.1 简述 时间有限使用VMware6.7环境使用Centos7.8最小化安装方式(不用配置本地yum仓库)注意查看主机名(主机双机操作,部分单机操作) 序号HostIPAd…...
爱思唯尔word模板
爱思唯尔word模板 有时候并不一定非得latex https://download.csdn.net/download/qq_38998213/90199214 参考文献书签链接...
交换机Vlan中 tagged和untagged的区别
pvid,tagged与untagged pvid是交换机一个端口上的id,一个端口只能有一个pvid,多个端口可以有相同的pvid。 一:接收数据 Untagged:不管收到的数据帧是否已经有VLAN标记,将数据帧中的vlan标记修改为自己的pvi…...
软件需求分析期末知识点整理
前言:本文为wk学子量身打造,帮助大家少挂科。主要根据ls的会议进行整理。懂得都懂。 重点还是多看看课本 第2章 需求获取的方法 第3章 3.1.2 控制需求(案例*2) 第4章 4.3 范式 第5章 5.2.3 原子功能(案例) 5.2.4 划分功能(案例)5.3.3 工作流图(画图) 第…...
PyAudio使用手册
PyAudio 是一个功能强大的 Python 库,用于在 Python 中进行音频输入和输出操作 1. 安装 在使用 PyAudio 之前,需要先安装它。可以使用 pip 进行安装: pip install pyaudio在某些系统(如 Ubuntu)上,可能还需…...
总结TCP/IP四层模型
总结TCP/IP四层模型 阅读目录(Content) 一、TCP/IP参考模型概述 1.1、TCP/IP参考模型的层次结构二、TCP/IP四层功能概述 2.1、主机到网络层 2.2、网络互连层 2.3、传输层 2.3、应用层 三、TCP/IP报文格式 3.1、IP报文格式3.2、TCP数据段格式3.3、UDP数据段格式3.4、套…...
《深入挖掘Python加解密:自定义加密算法的设计与实现》
利用python实现加解密 在正式编写各种加解密前,我们先写个小案例,如下。 封面在文末呦! 基础加解密-源码 # 加密 def encode():source01 乐茵for c in source01:ascii01 ord(c)ascii01 1print(chr(ascii01), end)# 解密 def decode():…...
【前端,TypeScript】TypeScript速成(六):函数
函数 函数的定义 定义一个最简单的加法函数: function add(a: number, b: number): number {return a b }(可以看到 JavaScript/TypeScript 的语法与 Golang 也非常的相似) 调用该函数: console.log(add(2, 3)) // out [LOG…...
Python中元组(tuple)内置的数据类型
在Python中,元组(tuple)是一种内置的数据类型,用于存储不可变的有序元素集合。元组在很多方面与列表(list)相似,但它们之间存在一些关键的区别。以下是关于Python元组的详细解释: 定…...
AI安全的挑战:如何让人工智能变得更加可信
引言 随着人工智能(AI)技术在各个领域的广泛应用,尤其是在医疗、金融、自动驾驶和智能制造等行业,AI正在重塑我们的工作和生活方式。从提高生产效率到实现个性化服务,AI带来了前所未有的便利。然而,在享受这…...
redis用途都有哪些
Redis,作为一个开源的高性能键值对数据库,其用途广泛且功能强大。 1. 缓存(Caching): • Redis常被用作缓存层,存储那些频繁访问但不易改变的数据,如用户会话、商品详情等。 • 通过将这些数据存…...
【Django篇】--动手实现路由模块化与路由反转
一、路由模块化 在一个Django项目中,由于功能类别不同,因此需要将不同功能进行模块化设计。在Django项目中模块化设计则需要将不同模块封装为对应的app模块,每一个模块中涉及到的路由则也需要进行模块化设计,才能更好的让整个项目…...
自研国产零依赖前端UI框架实战008 用户表单以及随机ID
前言 通过前面的努力,我们的组件已经越来越多了,我们的功能也越来越完善. 不过我们的新增用户的功能还没有做. 接下来, 就让我们实现新增用户的功能. 显示新增用户的表单 首先, 我们先把新增用户的表单显示出来. 我们可以复用之前的组件. <zdp_button1 text"新增…...
【数据结构-单调队列】力扣LCR 184. 设计自助结算系统
请设计一个自助结账系统,该系统需要通过一个队列来模拟顾客通过购物车的结算过程,需要实现的功能有: get_max():获取结算商品中的最高价格,如果队列为空,则返回 -1 add(value):将价格为 value …...
项目管理和协作平台Maintainer、Guest、Reporter、Owner 和 Developer 是常见的用户角色
在项目管理和协作平台上,Maintainer、Guest、Reporter、Owner 和 Developer 是常见的用户角色,每个角色有不同的权限和责任。以下是这些角色的详细区别: 1. Guest(访客) 权限:最低级别的权限。访问&#…...
探索电商数据:爬取不同平台商品信息的Python实践
在数字化时代,电商平台的商品信息成为了宝贵的数据资源。除了亚马逊,全球还有许多电商平台的商品信息值得爬取。本文将介绍几个值得关注的电商平台,并提供Python代码示例,展示如何爬取这些平台的商品信息。 1. 京东 (JD.com) 京…...
Autoware Universe 安装记录
前提: ubuntu20.04,英伟达显卡。 演示:https://www.bilibili.com/video/BV1z4CbYFEwr/?spm_id_from333.337.search-card.all.click ROS2-Galactic安装 wget http://fishros.com/install -O fishros && . fishros 选择galactic(R…...
CAT3D: Create Anything in 3D with Multi-View Diffusion Models 论文解读
24年5月的论文,上一版就是ReconFusion 目录 一、概述 二、相关工作 1、2D先验 2、相机条件下的2D先验 3、多视角先验 4、视频先验 5、前馈方法 三、Method 1、多视角扩散模型 2、新视角生成 3、3D重建 一、概述 该论文提出一种CAT3D方法,实现…...
群落生态学研究进展▌Hmsc包对于群落生态学假说的解读、Hmsc包开展单物种和多物种分析的技术细节及Hmsc包的实际应用
HMSC(Hierarchical Species Distribution Models)是一种用于预测物种分布的统计模型。它在群落生态学中的应用广泛,可以帮助科学家研究物种在不同环境条件下的分布规律,以及预测物种在未来环境变化下的潜在分布范围。 举例来说&a…...
C 进阶 — 程序环境和预处理
C 进阶 — 程序环境和预处理 主要内容 程序的编译和执行环境 C 程序编译和链接 预定义符号 预处理指令 #define 预处理指令 #include 预处理指令 #undef 预处理操作符 # 和 ## 宏和函数对比 命令行定义 条件编译 一 程序的编译和执行环境 ANSI C 存在两个不同环境…...
基于单片机的温湿度采集系统(论文+源码)
2.1系统的功能 本系统的研制主要包括以下几项功能: (1)温度检测功能:对所处环境的温度进行检测; (2)湿度检测功能:对所处环境的湿度进行检测; (3)加热和制冷功能:可以完成加热和制冷功能。 (4)加湿和除…...
【数据分析处理之缺失值】
文章目录 一、缺失值的影响1. 统计分析的偏差2. 机器学习模型的性能下降3. 数据质量和可信度下降4. 数据利用率降低5. 增加数据预处理的复杂度 二、识别缺失值1. 使用工具识别缺失值2. 可视化缺失数据 三、处理缺失值的策略1. 删除含缺失值的行或列2. 填充缺失值a. 用常数填充b…...
【大模型实战篇】Mac本地部署RAGFlow的踩坑史
1. 题外话 最近一篇文章还是在11月30日写的,好长时间没有打卡了。最近工作上的事情特别多,主要聚焦在大模型的预训练、微调和RAG两个方面。主要用到的框架是Megatron-DeepSpeed,后续会带来一些分享。今天的文章主要聚焦在RAG。 近期调研了一系…...
SQL Server实现将分组的其他字段数据拼接成一条数据
在 SQL Server 中,可以使用 STRING_AGG 函数(SQL Server 2017 及更高版本支持)将分组的其他字段数据拼接成一条数据。以下是示例代码: 假设有一个表 Orders,结构如下: OrderIDCustomerIDProduct1C001Appl…...
STM32 高级 物联网通讯之蓝牙通讯
目录 蓝牙基础知识 蓝牙概述 蓝牙产生背景 蓝牙发展历程 蓝牙技术类型 经典蓝牙(BR/EDR和AMP) 低功耗蓝牙(BLE) 市场上常见蓝牙架构 SOC蓝牙单芯片方案 SOC蓝牙+MCU方案 蓝牙host+controller分开方案 蓝牙协议栈 蓝牙芯片架构 BLE低功耗蓝牙协议栈框架 物理…...
堆排序基础与实践:如何在Java中实现堆排序
目录 一、堆排序的基本原理 二、堆排序的实现步骤 三、堆排序的时间复杂度和空间复杂度 四、堆排序的工作流程 五、堆排序的优缺点 六、堆排序的应用场景 堆排序(Heap Sort)是一种基于堆数据结构的排序算法。堆是一种特殊的完全二叉树,…...
你有哪些Deep Learning(RNN、CNN)调参的经验?
在深度学习的实践中,调参是一项既艺术又科学的工作。它不仅需要理论知识的支撑,还需要大量的实践经验。以下是一些在RNN和CNN模型调参中积累的经验,希望对正在这个领域摸索的朋友们有所帮助。 1. 从成熟的开源项目开始 对于初学者来说&…...
小程序租赁系统开发的优势与应用探索
内容概要 在如今这个数码科技飞速发展的时代,小程序租赁系统开发仿佛是一张神奇的魔法卡,能让租赁体验变得顺畅如丝。想象一下,无论你需要租用什么,从单车到房屋,甚至是派对用品,只需动动手指,…...
Spring Boot教程之三十九: 使用 Maven 将 Spring Boot 应用程序 Docker 化
如何使用 Maven 将 Spring Boot 应用程序 Docker 化? Docker是一个开源容器化工具,用于在隔离环境中构建、运行和管理应用程序。它方便开发人员捆绑其软件、库和配置文件。Docker 有助于将一个容器与另一个容器隔离。在本文中,为了将Spring B…...
Day58 图论part08
拓扑排序精讲 拓扑排序看上去很复杂,其实了解其原理之后,代码不难 代码随想录 import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();List<List<Integer&…...
u3d中JSON数据处理
一.认识JSON 1.1 Json概述 JSON(JavaScript Object Notation,JavaScript对象表示法)JSON和XML是比较类似的技术,都是用来存储文本信息数据的;相对而言,JSON比XML体积更小巧,但是易读性不如XML…...
大语言模型(LLM)一般训练过程
大语言模型(LLM)一般训练过程 数据收集与预处理 收集:从多种来源收集海量文本数据,如互联网的新闻文章、博客、论坛,以及书籍、学术论文、社交媒体等,以涵盖丰富的语言表达和知识领域。例如,训练一个通用型的LLM时,可能会收集数十亿甚至上百亿字的文本数据.清洗:去除…...
第十六届蓝桥杯模拟赛(第一期)(C语言)
判断质因数 如果一个数p是个质数,同时又是整数a的约数,则p称为a的一个质因数。 请问2024有多少个质因数。 了解 约数,又称因数。整数a整除整数b,b为a的因数(约数)质数,又称素数。只有1和它本身两…...
某网站手势验证码识别深入浅出(全流程)
注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 本文识别已同步上线至OCR识别网站: http://yxlocr.nat300.top/ocr/other/20 本篇文章包含经验和教训总结,我采用了两种方法进行识别,两种方法都各有优劣,其中一…...
QT---------QT框架功能概述
常用Qt界面组件 Qt提供了丰富的界面组件,如QPushButton(按钮)、QLineEdit(单行文本框)、QTextEdit(多行文本框)、QLabel(标签)、QComboBox(下拉框࿰…...
C++ 设计模式:模板方法(Template Method)
链接:C 设计模式 链接:C 设计模式 - 策略模式 链接:C 设计模式 - 观察者模式 模板方法(Template Method)是一种行为设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。通过这…...
下载mysql免安装版和配置
1、下载地址 点击去官网下载https://downloads.mysql.com/archives/community/ 2、解压安装mysql 解压的文件夹是没有my.ini文件和data目录,需要我们自己去创建 根目录下创建my.ini,根目录创建data [mysql] default-character-setutf8[mysqld] #端口 po…...
Web服务端技术原理及应用
前言 黄色的是考点,蓝色的是重点。 HTML/CSS/JS 本章会有一个7分的程序设计题,用到前端知识 form表单元素,常用表单元素 html:HTML快速上手 基础语法、css常用选择器(ID、类)、盒子模型 css:网页美化指南 JS …...
数据库的使用09:使用SSMS工具将SQLsever数据导出到Excel
第一步,新建一个空白的.csv文件 第二步,按步骤点击导出 第三步,选择数据源(Db数据库) 第四步,选择目标源(CSV平面文件目标) 第五步,指定表或SQL 一直点下一步即可&am…...
Python中__getitem__ 魔法方法
在Python中,__getitem__ 是一个特殊的方法,通常称为“魔法方法”或“双下方法”(因为它们的名字前后都有两个下划线)。__getitem__ 方法允许一个对象实现像序列(如列表、元组、字符串)一样的行为࿰…...
自动驾驶三维重建
大概八成估计是未来的科研方向了 Neural Radiance Field in Autonomous Driving: A Survey...
小程序中引入echarts(保姆级教程)
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...
INNER JOIN,LEFT JOIN,RIGHT JOIN,FULL JOIN这四个怎么在gorm中使用
在 GORM 中,JOIN 操作是通过 Joins 方法实现的,而不同类型的 JOIN(如 INNER JOIN、LEFT JOIN、RIGHT JOIN 和 FULL JOIN)可以通过特定的 SQL 语法来表示。GORM 本身并没有直接的 INNER, LEFT, RIGHT 等专用方法,但可以…...