簡體   English   中英

套接字寫入 for 循環混合字符串緩沖區

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM