我正在寻找最有效的解决方案,有很多方法可以从套接字读取数据和解码 json。我显然应该使用 json.Encoder 和 json.Decoder,因为它们适合套接字的流式处理,但我有防止套接字泛滥的特定规则,如果单个消息大于 5 Kb,我必须关闭连接。我的消息结构是 JSON RPC。
在下面的示例中,我可以检查长度并应用策略:
connbuf := bufio.NewReader(conn)
msg, err := connbuf.ReadBytes('\n')
if len(msg) > 5 * 1024 {
conn.Close()
}
...
var req JSONRequest
err = json.Unmarshal(message, &req)
...
但是如果客户端推送数兆字节的数据而没有定界符,这些数据将在应用程序中,在服务器断开客户端连接之前已经在 msg 变量中。非常脆弱。
第二个例子使用解码器,根本没有机会检查大小。
dec = json.NewDecoder(conn)
for {
var req JSONRequest
if err := dec.Decode(&req); err == io.EOF {
break
} else if err != nil {
log.Println(err.Error())
return err
}
...
}
您能向我建议的最佳方法是什么?谢谢。
最佳答案
对于第一个示例,您可以使用 ReadLine
:
connbuff := bufio.NewReaderSize(conn, 5*1024)
msg, isPrefix, err := connbuff.ReadLine()
if isPrefix {
// too long
}
...
如果 isPrefix
为真,则该行太长。如果您使用 bufio.Scanner
,它实际上已经具有 64kb 的最大 token 大小。
正如 Tim Cooper 和 Dave C 所说,对于第二种情况,您可以使用 io.LimitedReader
,但是 json 解码器有一个陷阱。它使用缓冲 IO,因此它会读取第一个请求。
要解决这个问题,请结合使用 io.MultiReader
和 io.LimitReader
:
// to start with we have nothing buffered (an empty byte slice)
var buffered io.Reader = bytes.NewReader([]byte{})
for {
// combine whatever was in buffered with conn, but only up to 5kb
dec := json.NewDecoder(io.LimitReader(io.MultiReader(buffered, conn), 5*1024))
var req string
err := dec.Decode(&req)
if err == io.EOF {
break
} else if err != nil {
log.Fatalln(err)
}
// we probably read past the message, so save that to buffered
buffered = dec.Buffered()
}
关于go - 如何高效实现json tcp server并防止socket flood?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30220247/