0

0

如何在Golang中自定义Bufio.Scanner的分隔符 Go语言解析复杂文本协议

P粉602998670

P粉602998670

发布时间:2026-03-12 09:45:32

|

235人浏览过

|

来源于php中文网

原创

默认的 bufio.scanner 读不到换行符以外的协议边界,因其默认使用 bufio.scanlines,仅识别 \n 或 \r\n;需自定义 split 函数(如支持 smtp/pop3 的 \r\n.\r\n),注意处理跨缓冲区匹配与行首敏感逻辑。

如何在golang中自定义bufio.scanner的分隔符 go语言解析复杂文本协议

为什么默认的 bufio.Scanner 读不到换行符以外的协议边界

因为 bufio.Scanner 默认用 bufio.ScanLines 作分隔逻辑,它只认 \n(或 \r\n),对自定义帧头、长度前缀、特殊结束标记(比如 "\r\n.\r\n")完全无感。你看到 scanner.Token() 总是截断在第一个换行,不是 bug,是设计如此。

解决办法是传入自定义的分割函数——但注意:Scan() 内部会缓存数据,如果分隔符跨缓冲区(比如分隔符横跨两个 4KB 块),你的函数必须能处理「不完整匹配」,否则直接丢数据。

  • scanner.Split() 注册函数,该函数签名必须是 func(data []byte, atEOF bool) (advance int, token []byte, err error)
  • atEOFtrue 时,表示底层 Reader 已无新数据,此时若还没找到分隔符,得决定是返回剩余数据还是报错
  • 别在分割函数里做字符串解码(如 string(data)),避免重复分配;用 bytes.Index 或手动字节比对更稳

怎么写一个支持 "\r\n.\r\n" 的邮件协议分隔函数

SMTP/POP3 协议常用 "\r\n.\r\n" 标记消息体结束,这个分隔符有 5 字节,且中间含点号,不能简单用 bytes.Contains 扫描——它可能误触发在正文里的孤立 "\r\n.\r\n"(比如用户发了一行只有英文句点的内容)。

正确做法是:只在行首位置检查 "\r\n." 后跟 \r\n,也就是模拟真实协议解析器的「行边界敏感」行为。

立即学习go语言免费学习笔记(深入)”;

ColorMagic
ColorMagic

AI调色板生成工具

下载
func dotCRLF(data []byte, atEOF bool) (advance int, token []byte, err error) {
	if atEOF && len(data) == 0 {
		return 0, nil, nil
	}
	for i := 0; i < len(data)-4; i++ {
		if data[i] == '\r' && data[i+1] == '\n' && data[i+2] == '.' && data[i+3] == '\r' && data[i+4] == '\n' {
			return i + 5, data[0:i], nil
		}
	}
	if atEOF {
		return len(data), data, nil // 返回剩余未结束的数据
	}
	return 0, nil, nil // 暂不推进,等更多数据
}
  • 这个函数不拷贝原始 datatoken 是切片引用,零分配
  • 没找到分隔符且 atEOF==false 时返回 (0, nil, nil),scanner 会继续读;这是关键,漏掉就卡死
  • 如果协议要求严格校验「点转义」(如 ".." 表示真实句点),那得在提取 token 后额外做一次解码,分割函数本身不负责

bufio.Scanner 的缓冲区大小和超限错误怎么调

默认缓冲区是 64KB,遇到超长行(比如 base64 编码的大附件)会直接报 bufio.ErrTooLong,而不是继续扫描。这不是分隔逻辑问题,是内存保护机制。

调缓冲区要两步:先用 scanner.Buffer() 设上限,再确保底层 io.Reader 能持续供数(比如不要用 strings.NewReader 模拟大文本,它不体现流式压力)。

  • scanner.Buffer(make([]byte, 4096), 10*1024*1024) 表示初始 4KB、上限 10MB
  • 设太大可能 OOM;设太小会导致频繁 realloc,实测 1–4MB 在多数协议解析中较平衡
  • ErrTooLongerror 类型,不是 panic,必须显式检查 scanner.Err(),否则静默失败
  • 如果协议本身禁止超长帧(如 HTTP/2 帧最大 16KB),那应该在业务层校验,而非靠 scanner 缓冲区硬扛

bufio.Scanner 解析二进制协议容易踩哪些坑

它本质是面向文本设计的,所有分隔逻辑都基于字节比较,但二进制协议常含 \x00、控制字符、不定长字段——这时 scanner.Split() 仍可用,只是你写的分割函数得更小心。

  • 别依赖 strings 包函数(如 strings.Index),它们把 []bytestring 会复制且对 \x00 不友好;坚持用 bytes.Index 或手写循环
  • 如果分隔符本身是变长的(如 TLV 中的 length 字段后跟 payload),scanner.Split 就不适用了——它只能按「已知字节模式」切,无法动态读取长度再跳;此时应直接用 bufio.Reader.Read() + 手动状态机
  • 注意字节序:如果你的分隔符含多字节整数(如 0x0000FFFF),别直接 memcmp,先用 binary.BigEndian.Uint16() 解出来再比

真正难的从来不是写对一个分隔函数,而是确认协议文档里那个「结束标记」到底有没有例外场景——比如是否允许嵌套、是否区分大小写、是否在注释块里失效。这些细节不厘清,代码写得再漂亮也白搭。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

247

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

356

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

214

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

409

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

201

2025.06.10

golang数组使用方法
golang数组使用方法

本专题整合了golang数组用法,想了解更多的相关内容,请阅读专题下面的文章。

1438

2025.06.17

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 6.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号