[英]socket write in for loop mixes string buffers
我使用這樣的 for 循環多次調用一個函數:
for ( int con=0; con < this->controller_info.size(); con++ ) {
try {
this->pi.home_axis( this->controller_info.at(con).addr );
}
catch( std::out_of_range &e ) { ... }
}
home_axis()
函數定義為:
long ServoInterface::home_axis( int addr ) {
std::stringstream cmd;
if ( addr > 0 ) cmd << addr << " ";
cmd << "FRF";
cmd << "\n";
int bytes=this->controller.Write( cmd.str() );
return NO_ERROR;
}
並且controller.Write()
函數只是標准write(2)
的包裝器,它將字符串中的字符寫入套接字文件描述符。
您可以看到,每次調用home_axis()
時,它都應該有自己的、新鮮的std::stringstream cmd
緩沖區。 但是發生的情況是,第一次執行 for 循環時,正在接收 home_axis 寫入的字節的主機正在接收一個字符串,一次:
1 FRF2 FRF
但是如果我打印寫入的字節,那么它會打印 6,兩次。 所以寫入器是正確寫入的,兩次不同的 6 個字節,但主機顯然將它作為單個緩沖區接收。
如果我再次執行該 for 循環,則主機(正確)接收,
1 FRF
接着
2 FRF
處理兩個接收到的緩沖區,因為它們分別進入。
std::stringstream cmd
緩沖區怎么會像這樣混合?
這里不涉及線程。
為了稍微區分一下,如果我在那個 for 循環中插入 1µsec 的延遲,即usleep(1);
然后它可以正常工作。 另外,如果我手動調用home_axis()
函數,但同樣快速連續,而不使用這樣的 for 循環,
this->pi.home_axis( this->controller_info.at(0).addr );
this->pi.home_axis( this->controller_info.at(1).addr );
那么這也有效。
所以我想知道是否有可能正在進行編譯器優化?
這與編譯器完全無關。
TCP 是一個字節流。 它沒有消息邊界的概念。 寫入和讀取之間沒有 1:1 的關系。 您可以編寫 2 條消息,每條 6 字節,接收方可能一次接收全部 12 字節,或者 1 字節然后 11 字節,或者兩者之間的任何組合。 這就是 TCP 的工作方式。 默認情況下,它會根據它認為合適的方式分解數據包以優化傳輸。
重要的是 TCP 保證字節將被傳遞(除非連接丟失),並且它將以與寫入字節相同的順序傳遞字節。
因此,發送者必須在數據本身中指明每條消息的開始和結束位置。 通過在其內容之前發送消息的長度,或者通過使用唯一的分隔符分隔每條消息(如您所願)。
在接收端,單次讀取可能會接收到部分消息,或多條消息的片段等。接收方負責緩沖傳入字節並根據需要僅從該緩沖區中提取完整消息,無論讀取多少次。完成它們。
當您使用尾隨\n
分隔消息時,接收器應緩沖所有字節並僅提取已收到其\n
的消息,將任何不完整的消息留在緩沖區末尾以供后續讀取完成。
通過這種方式,消息邊界得以保留和正確處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.