【问题标题】:Server failing to parse packets when flooded too fast服务器在泛滥过快时无法解析数据包
【发布时间】:2014-11-29 11:16:10
【问题描述】:

这是我在每秒用太多数据包淹没服务器时遇到的错误:

2014/11/28 12:52:49 main.go:59: loading plugin: print
2014/11/28 12:52:49 main.go:86: starting server on 0.0.0.0:8080
2014/11/28 12:52:59 server.go:15: client has connected: 127.0.0.1:59146
2014/11/28 12:52:59 server.go:43: received data from client 127.0.0.1:59146: &main.Observation{SensorId:"1", Timestamp:1416492023}
2014/11/28 12:52:59 server.go:29: read error from 127.0.0.1:59146: zlib: invalid header
2014/11/28 12:52:59 server.go:18: closing connection to: 127.0.0.1:59146

它设法解码一个数据包(有时可能是 2 个或 3 个)然后出错。这是执行泛洪的代码:

import socket
import struct
import json
import zlib
import time

def serialize(data):
    data = json.dumps(data)
    data = zlib.compress(data)

    packet  = struct.pack('!I', len(data))
    packet += data

    return len(data), packet

message = {
    'sensor_id': '1',
    'timestamp': 1416492023,
}

length, buffer = serialize([message])

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect(('127.0.0.1', 8080))

while True:
    client.send(buffer)

    #time.sleep(0.0005)

当我取消注释 time.sleep() 调用时,服务器工作正常。似乎每秒有太多的数据包正在杀死服务器。为什么?

这是相关的 Go 代码。连接处理程序:

func (self *Server) handleConnection(connection net.Conn) {
    for {
        connection.SetReadDeadline(time.Now().Add(30 * time.Second))

        observations, err := self.Protocol.Unserialize(connection)

        if err != nil {
            log.Printf("read error from %s: %s\n", connection.RemoteAddr(), err)

            return
        }
}

这里是反序列化器:

// Length Value protocol to read zlib compressed, JSON encoded packets.
type ProtocolV2 struct{}

func (self *ProtocolV2) Unserialize(packet io.Reader) ([]*Observation, error) {
    var length uint32

    if err := binary.Read(packet, binary.BigEndian, &length); err != nil {
        return nil, err
    }

    buffer := make([]byte, length)
    rawreader := bufio.NewReader(packet)

    if _, err := rawreader.Read(buffer); err != nil {
        return nil, err
    }

    bytereader := bytes.NewReader(buffer)
    zreader, err := zlib.NewReader(bytereader)

    if err != nil {
        return nil, err
    }

    defer zreader.Close()

    var observations []*Observation

    decoder := json.NewDecoder(zreader)

    if err := decoder.Decode(&observations); err != nil {
        return nil, err
    }

    return observations, nil
}

【问题讨论】:

    标签: go server


    【解决方案1】:

    Python 脚本的客户端似乎有错误。

    没有检查 client.send 的返回,所以脚本没有以正确的方式处理部分写入。基本上,当socket缓冲区满时,只会写入部分消息,导致服务器无法解码消息。

    此代码已损坏,但添加等待使其工作,因为它会阻止套接字缓冲区满。

    您可以改用 client.sendall 来确保写入操作完成。

    Python 文档中的更多信息:

    https://docs.python.org/2/library/socket.html

    https://docs.python.org/2/howto/sockets.html#using-a-socket

    现在在 Go 服务器中,也有类似的问题。文档说:

    Read 将数据读入 p。它返回读入 p 的字节数。它在底层 Reader 上最多调用一次 Read,因此 n 可能小于 len(p)。在 EOF 时,计数为零,err 为 io.EOF。

    rawreader.Read 调用返回的字节数可能比您预期的要少。您可能需要使用 io 包的 ReadFull() 函数来确保读取完整的消息。

    【讨论】:

    • 啊,不错。将其从使用 client.send 更改为 client.sendall 略有改进,尽管错误仍然存​​在。它现在从出错前接收 ~2 个数据包变为接收 ~11 个数据包。同样的错误:read error from 127.0.0.1:43918: zlib: invalid header
    • 同样的问题,但这次是在 Go 服务器上。 rawreader.Read 调用返回的字节数可能比您预期的要少。
    • 没有想到这一点感到很愚蠢。干杯,我会调查一下。
    • 你很准。从bufio.Read 更改为io.ReadFull 似乎已经清除了它。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多