草庐IT

golang - bufio 读取多行直到 (CRLF)\r\n 定界符

coder 2023-06-27 原文

我正在尝试实现我自己的 beanstalkd 客户端作为学习围棋的一种方式。 https://github.com/kr/beanstalkd/blob/master/doc/protocol.txt

目前,我正在使用 bufio读取由 \n 分隔的一行数据.

res, err := this.reader.ReadLine('\n')

当我发送单个命令并读取单行响应时,这很好:INSERTED %d\r\n但是当我尝试保留工作时我发现困难,因为工作主体可能是多行,因此我不能使用 \n分隔符。

有没有办法读入缓冲区直到CRLF

例如当我发送 reserve命令。我的预期响应如下:

RESERVED <id> <bytes>\r\n
<data>\r\n

但数据可能包含 \n , 所以我需要读到 \r\n .

或者 - 有没有一种方法可以读取 <bytes> 中指定的特定字节数?在上面的示例响应中?

目前,我有(删除错误处理):

func (this *Bean) receiveLine() (string, error) {
    res, err := this.reader.ReadString('\n')
    return res, err
}

func (this *Bean) receiveBody(numBytesToRead int) ([]byte, error) {
    res, err := this.reader.ReadString('\r\n') // What to do here to read to CRLF / up to number of expected bytes?

    return res, err
}

func (this *Bean) Reserve() (*Job, error) {

    this.send("reserve\r\n")
    res, err := this.receiveLine()

    var jobId uint64
    var bodylen int
    _, err = fmt.Sscanf(res, "RESERVED %d %d\r\n", &jobId, &bodylen)

    body, err := this.receiveBody(bodylen)

    job := new(Job)
    job.Id = jobId
    job.Body = body

    return job, nil
}

最佳答案

res, err := this.reader.Read('\n')

对我来说没有任何意义。您是指 ReadBytes/ReadSlice/ReadString 吗?

你需要 bufio.Scanner。

定义您的 bufio.SplitFunc(示例是 bufio.ScanLines 的副本,并进行了修改以查找“\r\n”)。修改它以符合您的情况。

// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
    if len(data) > 0 && data[len(data)-1] == '\r' {
        return data[0 : len(data)-1]
    }
    return data
}


func ScanCRLF(data []byte, atEOF bool) (advance int, token []byte, err error) {
        if atEOF && len(data) == 0 {
            return 0, nil, nil
        }
        if i := bytes.Index(data, []byte{'\r','\n'}); i >= 0 {
            // We have a full newline-terminated line.
            return i + 2, dropCR(data[0:i]), nil
        }
        // If we're at EOF, we have a final, non-terminated line. Return it.
        if atEOF {
            return len(data), dropCR(data), nil
        }
        // Request more data.
        return 0, nil, nil
    }

现在,用您的自定义扫描仪包装您的 io.Reader。

scanner := bufio.NewScanner(this.reader)
scanner.Split(ScanCRLF)
// Set the split function for the scanning operation.
scanner.Split(split)
// Validate the input
for scanner.Scan() {
        fmt.Printf("%s\n", scanner.Text())
}

if err := scanner.Err(); err != nil {
        fmt.Printf("Invalid input: %s", err)
}

阅读bufio package's Scanner源码。

Alternatively - is there a way of reading a specific number of bytes as specified in in example response above?

首先你需要阅读“RESERVED\r\n”行。

然后你就可以使用

nr_of_bytes : = read_number_of_butes_somehow(this.reader)
buf : = make([]byte, nr_of_bytes)
this.reader.Read(buf)

LimitedReader .

但我不喜欢这种方法。

Thanks for this - reader.Read('\n') was a typo - I corrected question. I have also attached example code of where I have got so far. As you can see, I can get the number of expected bytes of the body. Could you elaborate on why you don't like the idea of reading a specific number of bytes? This seems most logical?

我想看看 Bean 的定义,尤其是读者的部分。 想象一下,这个计数器不知何故是错误的。

  1. 它很简短:您需要找到后面的“\r\n”并丢弃到那一点为止的所有内容?或不?那你为什么首先需要柜台?

  2. 它比它应该的更大(或者更糟的是它巨大!)。

    2.1 阅读器中没有下一条消息:很好,阅读比预期的要短,但没问题。

    2.2 有下一条消息等待:呸,你读了一部分,没有简单的方法可以恢复。

    2.3 巨大:即使消息只有 1 个字节,也无法分配内存。

这个字节计数器一般是用来验证消息的。 看起来 beanstalkd 协议(protocol)就是这种情况。

使用 Scanner,解析消息,检查长度与预期数字......利润

UPD

请注意,默认的 bufio.Scanner 无法读取超过 64k 的数据,请先使用 scanner.Buffer 设置最大长度。这很糟糕,因为您不能即时更改此选项,并且某些数据可能已被扫描仪“预”读取。

UPD2

思考我的最后更新。看看net.textproto它如何像简单状态机一样实现 dotReader。您可以先读取命令并检查有效负载的“预期字节数”来做类似的事情。

关于golang - bufio 读取多行直到 (CRLF)\r\n 定界符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37530451/

有关golang - bufio 读取多行直到 (CRLF)\r\n 定界符的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 匹配未转义的平衡定界符对 - 2

    如何匹配未被反斜杠转义的平衡定界符对(其本身未被反斜杠转义)(无需考虑嵌套)?例如对于反引号,我试过了,但是转义的反引号没有像转义那样工作。regex=/(?!$1:"how\\"#expected"how\\`are"上面的正则表达式不考虑由反斜杠转义并位于反引号前面的反斜杠,但我愿意考虑。StackOverflow如何做到这一点?这样做的目的并不复杂。我有文档文本,其中包括内联代码的反引号,就像StackOverflow一样,我想在HTML文件中显示它,内联代码用一些spanMaterial装饰。不会有嵌套,但转义反引号或转义反斜杠可能出现在任何地方。

  3. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  4. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

  5. ruby - 匹配大写字母并用后续字母填充,直到一定的字符串长度 - 2

    我有一个驼峰式字符串,例如:JustAString。我想按照以下规则形成长度为4的字符串:抓取所有大写字母;如果超过4个大写字母,只保留前4个;如果少于4个大写字母,则将最后大写字母后的字母大写并添加字母,直到长度变为4。以下是可能发生的3种情况:ThisIsMyString将产生TIMS(大写字母);ThisIsOneVeryLongString将产生TIOV(前4个大写字母);MyString将生成MSTR(大写字母+tr大写)。我设法用这个片段解决了前两种情况:str.scan(/[A-Z]/).first(4).join但是,我不太确定如何最好地修改上面的代码片段以处理最后一种

  6. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  9. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  10. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

随机推荐