【问题标题】:How can I use json.Decoder to decode a single json message and switch the connection to a different protocol going foward?如何使用 json.Decoder 解码单个 json 消息并将连接切换到不同的协议?
【发布时间】:2015-01-12 05:19:54
【问题描述】:

我正在开发一个基于 TCP 的代理,它必须首先在给定连接上以 json 格式进行 REQ/REPLY 握手。因为 JSON 是一个自定界协议,所以我使用 Go 的 json.Decoder 来完成这项工作,该工作做得很好。

这是我采取的步骤:

  1. 拨号连接到远程服务器
  2. 将单个 json 请求写入远程服务器 (REQ)
  3. 从同一远程服务器读取单个 json 回复(完成代理握手回复)
  4. 在有效的 json 握手后,将客户端连接传递到代码的另一部分,该部分将(继续)从此时开始切换到基于文本的协议。

问题是,当 json.Decoder 将数据读取到其内部缓冲区时,它可能可能读取比它需要的更多的数据,在这种情况下,json.Decoder has a Buffered() 方法返回一个带有其余数据。

这个数据(在 Buffered() 方法中可用)现在是基于文本的协议数据,需要在 json 握手完成后从连接中读取。但是,如果我在不考虑剩余缓冲区的情况下按原样传递连接,则连接将进入锁定状态,因为它正在等待读取这些永远不会到来的数据。处理基于文本的协议的代码 期望 一个 net.Conn 继续前进,一旦我将连接向前传递(在 json 握手之后),使用连接的代码就知道如何说在这一点上基于文本的协议。所以应该有明确的工作界限。

我的问题是解决此问题的理想方法是什么,因此我仍然可以利用 json.Decoder,但请确保当我将连接传递到代理中代码的不同部分时,我知道开始基于文本的协议的数据仍然是可读的。我不知何故需要在 json.Decoder 的 Buffered() 方法中获取剩余数据并将其放回连接前面,以便以后可以正确读取。

非常感谢任何见解。

【问题讨论】:

  • 连接上运行的是什么协议?您应该在自己的消息中用不同的内容将每个数据包装箱,至少类似于 [size][payload]。
  • @fabrizioM - 基于文本的协议是专有的换行符分隔协议。我考虑过按照您的建议做,但它似乎没有必要,因为 json 是自定界的,并且基于文本的协议由换行符定界……如果不是 json.Decoder 缓冲区中的剩余数据,一切正常。跨度>
  • 给定io.Reader,您可以编写自己的结构来实现io.Reader,这需要两件事-[]bytes 带有要提供的前缀和io.Reader,当前缀全部提供时使用。跨度>
  • @TomaszKłak - 是的,我一直在考虑这些方面的一些事情......我忘记提及的另一个约束:处理文本协议的代码不需要 io.Reader 而是网络.Conn 我可能无法更改。
  • @ralph-caraveo net.Conn 也是一个Interface,所以同样的原则应该适用。

标签: json tcp proxy go stream


【解决方案1】:

你可以试试

type ConnWithBuffIncluded struct{ //Implement net.Conn so can be passed through pipeline
    net.Conn
    json.Decoder
}

func (x ConnWithBuffIncluded) Read(p []byte) (n int, err error){ //Will Read both sources
    return io.MultiReader(x.Decoder.Buffered(), x.Conn).Read(p)
}

【讨论】:

  • 我最终得到了一个看起来与此非常相似的解决方案。虽然不是超级干净,但它可以完成工作。
猜你喜欢
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 2020-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多