如何使用json.Decoder解码单个json消息并将连接切换到其他协议?

问题描述:

I am working on a TCP-based proxy that must first do a REQ/REPLY handshake in json on a given connection. Because JSON is a self-delimiting protocol I reach for Go's json.Decoder to pull off this work which does the job nicely.

Here are the steps I take:

  1. Dial a connection to a remote server
  2. Write a single json request to a remote server (REQ)
  3. Read a single json reply from the same remote server (completing the proxy handshake REPLY)
  4. Upon a valid json handshake, pass the client connection onto another part of the code which will (going forward) switch to a text based protocol from this point on.

The problem is, when json.Decoder reads data into its internal buffer it can potentially read more data than it needs in which case the json.Decoder has a Buffered() method which gives back an io.Reader with the remainder of the data.

This data (available in the Buffered() method) is now the text-based protocol data which needs to get read from the connection after the json hand-shake did its work. But if I pass the connection forward as is without considering the left over buffer, the connection gets into a locked state because it is waiting to read this data which never comes. The code that deals with the text-based protocol expects a net.Conn going forward and once I pass the connection forward (after the json handshake has been made) the code utilizing the connection understands how to speak the text-based protocol at this point on. So there should be a clear boundary of work.

My question is what is the ideal way to solve this issue so I can still take advantage of the json.Decoder, but ensure that when I pass the connection to a different part of the code in my proxy I know the start of the data for the text-based protocol will still be readable. I somehow need to take the remaining data in the json.Decoder's Buffered() method and put that back in front of the connection so it can be properly read going forward.

Any insight is much appreciated.

我正在使用基于TCP的代理,该代理必须首先在给定的连接中在json中进行REQ / REPLY握手 。 因为JSON是一种自定界协议,所以我可以使用Go的json.Decoder来完成这项工作,从而很好地完成了这项工作。 p>

这是我要执行的步骤: p>

  1. 拨号到远程服务器的连接 li>
  2. 将单个json请求写入远程服务器(REQ) li>
  3. 从同一远程服务器读取单个json答复(完成代理握手REPLY) li>
  4. json握手,将客户端连接传递到代码的另一部分,从这一点开始(向前)将切换到基于文本的协议。 li> ol>

    问题是 ,当json.Decoder将数据读入其内部缓冲区时,它可能会潜在地 em>读取比所需更多的数据,在这种情况下, json.Decoder具有Buffered()方法,该方法会返回io.Reader以及其余数据。 p>

    此 数据(在Buffered()方法中可用)现在是基于文本的协议数据,需要在json握手完成工作后从连接中读取。 但是,如果我按原样通过连接而不考虑剩余的缓冲区,则连接将进入锁定状态,因为它正在等待读取该数据,而该数据永远不会出现。 处理基于文本的协议的代码期望 em> net.Conn a>向前,一旦我将连接向前传递(在完成json握手之后),利用该连接的代码就可以理解此时如何说基于文本的协议。 所以应该有一个明确的工作边界。 p>

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

    任何见解都很多 表示赞赏。 p> div>

You can try

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)
}