go - 如何高效实现json tcp server并防止socket flood?

标签 go

我正在寻找最有效的解决方案,有很多方法可以从套接字读取数据和解码 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.MultiReaderio.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/

相关文章:

json - 将 interface{} 转换为 json 编码中的结构

testing - 如何在go test中设置日志级别?

linux - 在子级中安装seccomp过滤器

go - 如何编译 Go 程序?

go - 在 Go Wire 注入(inject)中使用单例模式

postgresql - 使用 go 和 sqlc 库创建 api 时,我在 postgresql 中的数据会自动加密

postgresql - golang使用终端命令迁移未知驱动程序postgresql

go - 如何强制 Protobuf 3 字段?

go - 配置[执行构建]/[执行测试]等以在诊断消息中显示绝对路径

go - 当我对指针变量使用不同的赋值运算符时,程序的行为有所不同