Golang和不工作的函数bytes.Contains()

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang和不工作的函数bytes.Contains()相关的知识,希望对你有一定的参考价值。

我有功能bytes.Contains(b, subslice []byte) bool的奇怪问题。它没有在函数(c *IPConn) Read(b []byte) (int, error)中收到的字节数组中找到字符。应用程序是一个简单的服所以我有字节数组,通过服务器接收到变量buf

buf := make([]byte, 1024)
Len, err := c.conn.Read(buf)
// below received content in buf
//{"abc":[{"b":5,"bca":14,"xyz":0}]}{"abc":[{"b":7,"hjk":14,"qwe":0}]}

现在我想使用下面的函数来查找} {数组buf中的字符

if bytes.Contains(buf, []byte(`}{`) != false {
    fmt.Printf("I got you")
}

但是函数总是返回false。为什么?

我在我的程序中做了一些实验,如下所示:

worker := []byte('{"abc":[{"b":5,"bca":14,"xyz":0}]}{"abc":[{"b":7,"hjk":14,"qwe":0}]}')

// try find }{

if bytes.Contains(worker, []byte(`}{`) != false {
    fmt.Printf("I got you")
}

是正确的 !!!我不明白这一点......因为它允许通过服务器接收的数据和通常在程序中附加的数据之间的内容必须不同。

答案

err结束后你真的检查Lenc.conn.Read(buf)吗?

程序中的主要缺陷(如图所示)是你正在使用buf来搜索数据,而套接字上的读取操作在收到1到1024之间的任意数量的字节后可以自由地返回,并在返回后出错接收0到1024之间的任意数量的字节。

所以,你必须做两件事:

  • Check for error;
  • 要在读取操作结束后访问缓冲区开头可用的实际数据,您必须使用实际的数据长度Len

要做后者,通常构造一个新切片:

data := buf[:Len]

然后使用data变量:

if bytes.Contains(data, []byte("}{")) {
   ...
}

如果不这样做,您可以轻松访问缓冲区中的陈旧数据 - 也就是前一次调用c.conn.Read(buf)时留下的数据。

如果您再考虑一下这种情况,您会发现没有什么可以保证下一次调用套接字上的Read()会将}{序列带入缓冲区,并且您必须为累积数据做好准备:这是,

  1. 每次调用Read()都应将其Len字节添加到缓冲区中的字节数,以供代码考虑。 这意味着如果第N次读操作无法提供您正在查找的数据,则第(N + 1)次操作必须将其字节放在上一次读操作的最后一个字节之后;在Go中,这通常意味着为下一个读操作构造另一个片。
  2. 您应该使用总当前累计字节数来搜索“} {”。

请考虑从this book开始,掌握网络编程的基础知识(使用Go细节)。


如您所见,正确处理此任务看起来很复杂。那么为什么不让Go自己做缓冲呢?

你可以像这样重述你的algorythm:

  1. 读取输入数据,直到找到}字符。累积这些数据。
  2. 一旦找到},读下一个字符,如果它是{,我们找到了我们感兴趣的地方。 否则返回步骤(1)。

使用bytes.Buffer及其方法是可行的:

  • ReadBytes(delim byte) - 读取}字节。
  • ReadByte() - 用于读取单个字节以检查是否跟随{
  • UnreadByte(c byte) - 用于将字节放回缓冲区,如果它不是{之后的}

现在让我们从更一般的角度来看待你的问题。您在示例中显示的数据对我来说就像是一系列JSON对象。那么为什么你要尝试应用一些低技术方法来找到这些对象之间的边界,而不是仅使用JSON decoder来立即解码数据或者至少正确地跳过流中的对象?

另一答案

您的代码缺少某些括号等有问题。这似乎有效:

package main

import (
    "bytes"
    "fmt"
)

const data = `{"abc":[{"b":5,"bca":14,"xyz":0}]}{"abc":[{"b":7,"hjk":14,"qwe":0}]}`

func main() {

    buf := []byte(data)
    fmt.Printf("buf = %s
", string(buf))

    if bytes.Contains(buf, []byte("}{")) {
        fmt.Printf("I got you
")
    }

}

在您连接的应用程序中接收数据时可能存在编码问题,这是一个难以展示的问题,我偶尔会打印接收数据的十六进制值来真正看到线路上的内容。

编辑:

尝试打印出收到的数据,如下所示:

for _, b := range buf {
    fmt.Printf("%X ", b)
}

然后与测试数据进行比较,看看是否存在差异,这就像你说的那样唯一可能出错的地方?

以上是关于Golang和不工作的函数bytes.Contains()的主要内容,如果未能解决你的问题,请参考以下文章

以 constexpr 和不带 constexpr 的形式运行函数

Golang 中哪些值是不可以寻址的

带和不带 lambda 的 pandas apply()

GO语言异常处理机制panic和recover分析

golang 函数笔记

Golang的append工作流程