为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
凤凰求蛊 2021-11-08 17:01:44
我有函数的奇怪问题bytes.Contains(b, subslice []byte) bool。它没有在函数中接收到的字节数组中找到字符(c *IPConn) Read(b []byte) (int, error)。应用程序是一个简单的服务器。所以我有字节数组,它是通过服务器接收到的变量bufbuf := 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")}是正确的 !!!我不明白这一点......因为它允许通过服务器接收的数据之间的内容必须不同,并且数据形式通常是程序中的附件。
查看完整描述

2 回答

?
万千封印

TA贡献1891条经验 获得超3个赞

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

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

所以,你必须做两件事:

  • 检查错误

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

要执行后者,您通常会构造一个新切片:

data := buf[:Len]

然后使用data变量:

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

   ...

}

如果您不这样做,您可能很容易访问缓冲区中的陈旧数据 — 即,上次调用c.conn.Read(buf).

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

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

    这意味着如果第 N 个读取操作未能提供您要查找的数据,则第 (N+1) 个操作必须将其字节放在前一个读取操作的最后一个字节之后;在 Go 中,这通常意味着为下一个读取操作构造另一个切片。

  2. 您应该使用当前累积的总字节数来搜索“}{”。

请考虑从本书开始,以掌握网络编程的基础知识(与 Go 相关的细节)。


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

你可以这样重申你的算法:

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

  2. 一旦}被发现,读取下一个字符,如果是{,我们已经找到了点,我们感兴趣的问题。

    否则返回步骤(1)。

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

  • ReadBytes(delim byte)— 最多读取一个}字节。

  • ReadByte()— 用于读取单个字节以检查是否{跟随。

  • UnreadByte(c byte)— 用于将字节放回缓冲区,如果它不是{后续}.


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


查看完整回答
反对 回复 2021-11-08
?
狐的传说

TA贡献1804条经验 获得超3个赞

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


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\n", string(buf))


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

        fmt.Printf("I got you\n")

    }


}

在您连接的应用程序中接收数据可能存在编码问题,这是一个棘手的问题,我有时会使用打印接收数据的十六进制值来真正查看线路中出现的内容。


编辑 :


尝试像这样打印出接收到的数据:


for _, b := range buf {

    fmt.Printf("%X ", b)

}

然后和测试数据对比看看有没有差异,这是你说的唯一可能出错的地方吗?


查看完整回答
反对 回复 2021-11-08
  • 2 回答
  • 0 关注
  • 280 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信