douchen3562 2015-05-13 16:16
浏览 38
已采纳

如何有效地实现json tcp服务器并防止套接字泛滥?

I am searching for most efficient solution, there are a lot of ways to read data from socket and decode json. I obviously should use json.Encoder and json.Decoder, because they are suitable for streaming nature of socket, but I have specific rule to prevent socket flooding, I must close connection if there is a single message > than 5 Kb. My message structure is JSON RPC.

In the following example I can check length and apply policy:

connbuf := bufio.NewReader(conn)
msg, err := connbuf.ReadBytes('
')
if len(msg) > 5 * 1024 {
    conn.Close()
}
...
var req JSONRequest
err = json.Unmarshal(message, &req)
...

But if client pushes megabytes of data without delimiter, this data will be in application, in msg variable already before server will disconnect client. Pretty vulnerable.

Second example uses Decoder, there is no chance to check size at all.

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

What is the best approach you can suggest to me? Thanks.

  • 写回答

1条回答 默认 最新

  • doujingya1166 2015-05-13 22:54
    关注

    For the first example you can use ReadLine:

    connbuff := bufio.NewReaderSize(conn, 5*1024)
    msg, isPrefix, err := connbuff.ReadLine()
    if isPrefix {
      // too long
    }
    ...
    

    If isPrefix is true then the line was too long. If you used a bufio.Scanner it actually already has a max token size of 64kb.

    As Tim Cooper & Dave C said you can use io.LimitedReader for the second case, but there's one gotcha with the json decoder. It uses buffered IO, so it will read past the first request.

    To fix that use a combination of io.MultiReader and 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()
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 drone 推送镜像时候 purge: true 推送完毕后没有删除对应的镜像,手动拷贝到服务器执行结果正确在样才能让指令自动执行成功删除对应镜像,如何解决?
  • ¥15 求daily translation(DT)偏差订正方法的代码
  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler