我正在嘗試通過 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()}然后在receiver端,下面是我的接收方式。reader *bufio.Readerfor 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 } }現在我的問題是,如果發件人在中間中止他的寫入怎么辦:更具體地說,情況 1:如果發送方寫入消息類型字節,然后中止怎么辦?在這種情況下,接收方將讀取消息類型字節,并等待接收 8 字節的消息長度,但發送方不發送它。情況 2:這是情況 1 的擴展版本,其中發送方首先僅發送消息類型字節,中止發送消息長度和編組消息,然后發送下一條消息:類型字節、長度和編碼消息。現在在接收方,一切都出錯了,因為違反了消息的順序(類型、長度和編碼消息)。所以我的問題是,如何修改接收方,使其在發送方違反預先約定的 type:length:encoded-message 順序的情況下仍能繼續運行?
1 回答

慕少森
TA貢獻2019條經驗 獲得超9個贊
為什么發件人會中止一條消息,然后發送另一條消息?你的意思是它是一個完全拜占庭式的發件人?還是您正在準備進行模糊測試?
如果您的 API 合同規定發送方始終需要發送正確的消息,那么接收方可以簡單地忽略錯誤消息,甚至可以在發現違反 API 合同的情況下關閉連接。
如果你真的需要它,這里有一些關于如何讓它工作的想法:
從一個獨特的序言開始——但是你必須確保這個序言永遠不會出現在數據中
在將消息發送到解碼器之前向消息添加校驗和。所以完整的數據包將是
[msg_type : msg_len : msg : chksum ]
:這允許接收方檢查它是正確的消息還是格式錯誤的消息。
此外,就目前的代碼而言,發送最大 64 位的大小很容易導致崩潰。所以你還應該檢查大小是否在一個有用的范圍內。我會將其限制為 32 位...
- 1 回答
- 0 關注
- 112 瀏覽
添加回答
舉報
0/150
提交
取消