gpt4 book ai didi

go - TCP Protobuf消息在Go服务器的接收方不一致到达

转载 作者:行者123 更新时间:2023-12-03 10:10:13 24 4
gpt4 key购买 nike

我有一个“代理”,它将二进制文件解析为缓冲区,并且每当该缓冲区被填充时,就会通过protobuf消息将其发送到服务器,然后继续进行下一个二进制解析,然后再次发送,依此类推。
在服务器上,我使用简单的net/conn软件包,该软件包监听代理连接,并在while-for循环中将其从其中读取到缓冲区中。
解析完成后,代理程序端会在protobuf消息中发送terminate bool,表明这是最后一条消息,服务器可以继续处理接收到的完整数据。
但是,如果我将调试打印留在发送方,则效果很好,这会使终端打印大大降低了通过connection.Write()发送随后的protobuf消息的时间间隔。
如果我取消注释此记录器,则它发送消息的速度过快,并且服务器首先处理的传入消息是一个包含terminate标志的数据包,例如,它没有实际的有效负载,但立即接收到LAST消息。
我知道TCP并没有真正区分不同的[] byte数据包,这很可能是造成这种现象的原因。有其他更好的方法吗?
伪代码代理方:

    buffer := make([]byte, 1024)
for {
n, ioErr := reader.Read(buffer)
if ioErr == io.EOF {
isPayloadFinal = true

// Create protobuf message
terminalMessage, err := CreateMessage_FilePackage(
2234,
protobuf.MessageType_PACKAGE,
make([]byte, 1),
isPayloadFinal,
)
// Send terminate message
sendProtoBufMessage(connection, terminalMessage)
break
}
// Create regular protobuf message
message, err := CreateMessage_FilePackage(
2234,
protobuf.MessageType_PACKAGE,
(buffer)[:n],
isPayloadFinal)
sendProtoBufMessage(connection, message)
}
伪代码服务器端:
    buffer := make([]byte, 2048)
//var protoMessage protoBufMessage

for artifactReceived != true {
connection.SetReadDeadline(time.Now().Add(timeoutDuration))
n, _ := connection.Read(buffer)
decodedMessage := &protobuf.FileMessage{}
if err := proto.Unmarshal(buffer[:n], decodedMessage); err != nil {
log.Err(err).Msg("Error during unmarshalling")
}

if isPackageFinal := decodedMessage.GetIsTerminated(); isPackageFinal == true {
artifactReceived = true
log.Info().Msg("Artifact fully received")
/* Do stuff here */
break
}
// Handle partially arrived bytestream
handleProtoPackage(packageMessage, artifactPath)
} else {
fmt.Println("INVALID PROTOBUF MESSAGE")
}
}
和proto文件供引用:
message FilePackage{
int32 id = 1;
MessageType msgType = 2;
bytes payload = 3;
bool isTerminated = 4;

}

最佳答案

正如您所说,最可能的原因似乎是“TCP并没有真正区分不同的[] byte数据包”(TCP流没有消息边界)。当您调用connection.Read(buffer)(我假设connectionnet.Conn)时,它将阻塞直到有可用数据(或达到读取期限),然后返回该数据(直到缓冲区大小)。返回的数据可能是一条消息(如您​​在测试中所见),但也可能是部分消息,也可能是多条消息(取决于时序和网络堆栈;您不应做任何假设)。
protobuf docs提供了一种建议的技术:

If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins. The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own. The easiest way to solve this problem is to write the size of each message before you write the message itself. When you read the messages back in, you read the size, then read the bytes into a separate buffer, then parse from that buffer.


如果采用这种方法,则可以在接收数据时使用 io.ReadFull (因为您将知道期望大小的字节数,然后将其用于接收数据包)。

关于go - TCP Protobuf消息在Go服务器的接收方不一致到达,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64954996/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com