我正在嘗試通過 TCP 在 GoLang 中發送和接收 protobuff 編碼的訊息,發送方可以write()在操作中途取消,接收方可以正確接收部分訊息。
請注意,我使用單個 TCP 連接無限發送不同用戶定義型別的訊息(這不是每個連接訊息的情況)
為了具體解釋我的問題,首先我將介紹如何在沒有部分寫入的情況下實作發送/接收。
在我的程式中,有多種型別的訊息,定義在一個.proto檔案中。我將解釋一種此類訊息型別的機制。
message MessageType {
int64 sender = 1;
int64 receiver = 2;
int64 operation = 3;
string message = 4;
}
然后我使用 Golang Protobuf 插件來生成存根。
然后在發送方,下面是我的發送方式。
func send(w *bufio.Writer, code uint8, oriMsg MessageType) {
err := w.WriteByte(code)
data, err := proto.Marshal(oriMsg)
lengthWritten := len(data)
var b [8]byte
bs := b[:8]
binary.LittleEndian.PutUint64(bs, uint64(lengthWritten))
_, err = w.Write(bs)
_, err = w.Write(data)
w.flush()
}
然后在接收端,下面是我的接收方式。
reader *bufio.Reader
for true {
if msgType, err = reader.ReadByte(); err != nil {
panic()
}
if msgType == 1 || msgType == 2{
var b [8]byte
bs := b[:8]
_, err := io.ReadFull(reader, bs)
numBytes := binary.LittleEndian.Uint64(bs)
data := make([]byte, numBytes)
length, err := io.ReadFull(reader, data)
msg *MessageType = new(GenericConsensus) // an empty message
err = proto.Unmarshal(data[:length], msg)
// do something with the message
} else {
// unknown message type handler
}
}
Now my question is, what if the sender aborts his writes in the middle: more concretely,
Case 1: what if the sender writes the message type byte, and then abort? In this case the receiver will read the message type byte, and waits to receive an 8 byte message length, but the sender doesn't send it.
Case 2: This is an extended version of case 1 where the sender first sends only the message type byte, and the aborts sending the message length and marshaled message, and then send the next message: the type byte, the length and encoded message. Now in the receiver side, everything goes wrong because the order of messages (type, length and encoded message) is violated.
So my question is, how can I modify the receiver such that it can continue to operate despite the sender violating the pre-agreed order of type:length:encoded-message?
Thanks
uj5u.com熱心網友回復:
為什么發送者會中止一條訊息,然后發送另一條訊息?你的意思是它是一個完全拜占庭式的發件人?或者你正在準備模糊測驗?
如果您的 API 合約規定發送方始終需要發送正確的訊息,那么接收方可以簡單地忽略錯誤訊息,甚至在發現違反 API 合約時關閉連接。
如果你真的需要它,這里有一些關于如何使它作業的想法:
- 從一個獨特的序言開始 - 但是你必須確保這個序言永遠不會出現在資料中
- 在將訊息發送到解碼器之前,將校驗和添加到訊息中。所以完整的資料包將是:
[msg_type : msg_len : msg : chksum ]. 這允許接收者檢查它是正確的訊息還是錯誤的訊息。
此外,就目前的代碼而言,發送最大為 64 位的大小很容易崩潰。因此,您還應該檢查大小是否在有用的范圍內。我會將其限制為 32 位...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/447710.html
標籤:go tcp 网络编程 协议缓冲区 protobuf-go
