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

Mbd*_*ded -1 go

我的功能有奇怪的问题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}]}
Run Code Online (Sandbox Code Playgroud)

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

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

但是函数总是返回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")
}
Run Code Online (Sandbox Code Playgroud)

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

kos*_*tix 9

你真的检查err和完成Lenc.conn.Read(buf)

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

所以,你必须做两件事:

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

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

data := buf[:Len]
Run Code Online (Sandbox Code Playgroud)

然后使用data变量:

if bytes.Contains(data, []byte("}{")) {
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 每次调用都Read()应该将其Len字节添加到缓冲区中的字节数,以供代码考虑.

    这意味着如果第N次读操作无法提供您正在查找的数据,则第(N + 1)次操作必须将其字节放在上一次读操作的最后一个字节之后; 在Go中,这通常意味着为下一个读操作构造另一个片.

  2. 您应该使用总当前累计字节数来搜索"} {".

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


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

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

  1. 读取输入数据,直到}找到一个字符.累积这些数据.

  2. 一旦}找到,请阅读下一个字符,如果是a {,我们就找到了我们感兴趣的地方.

    否则返回步骤(1).

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

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

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