簡體   English   中英

帶有boost :: asio :: read的EOF

[英]EOF with boost::asio::read

我在C ++中的客戶端/服務器應用程序遇到了一個小問題。 它使用boost :: asio進行遠程通信,使用協議緩沖區進行序列化。 在這里客戶:

// Time to write
char sizeMessage[20];
string content = request.SerializeAsString();
size_t request_length = content.size();            

boost::asio::write(s, boost::asio::buffer(content.c_str(), request_length));
boost::system::error_code error;

boost::asio::read(s, boost::asio::buffer(sizeMessage, 20));

int bufferSize = atoi(sizeMessage);
char* responseString = new char[bufferSize];        
size_t reply_length = boost::asio::read(s, boost::asio::buffer(responseString, bufferSize), boost::asio::transfer_all(), error);
if(!error){
    response.ParseFromArray((const void*)responseString, reply_length);
    success = true;                
}else{
    response.set_status(ExecResponse::ERROR);                
}


delete[] responseString;

在我的應用程序的這個特定場景中,服務器的響應可以在大小上變化,從幾個字節到幾個MB。 出於這個原因,服務器首先寫入輸出的大小,然后我用它來為我的緩沖區分配適量的內存。 出於某種原因,我在讀取數據時遇到錯誤(始終正確讀取大小)。 一點點的調試顯示asio.misc:2通過谷歌搜索我發現它是EOF(實際上讀取字節的數量小於緩沖區大小)。 服務器端:

ExecResponse response;
ExecutionServerHandler execHandler(this->sharedData);
execHandler.process(rd, request, response);   
string output = response.SerializeAsString();
//First write the length
ostringstream stringLength;
stringLength << output.size();
response.PrintDebugString();
string lengthString = stringLength.str();    
size_t bw = ba::write(bsocket_, ba::buffer(lengthString));
bw = ba::write(bsocket_, ba::buffer(output));

這實際上是我第一次使用boost,所以我不是一個經驗豐富的開發人員。 此外,重要的是要提到在我的應用程序的其他部分,這種機制有效,但我的其他消息有一些差異:雖然它們的大小仍然可變,但它們總是很小(幾百字節)。 服務器端是相同的,但在客戶端我使用boost :: asio :: transfer_at_least(1),我不提前寫大小。 如果我將這些更改應用於這種情況,我注意到讀取調用最多可以檢索65536個字節而不是更多(過早返回EOF)。 我的開發機器是64位的Debian 5和Ubuntu 10.04,我對Boost 1.40和1.47有相同的行為。 如果有人意識到我做錯了什么,我將不勝感激。 我很絕望,試圖讓它發揮作用。

在我看來你的協議可能存在問題:你的客戶如何知道lengthString的長度? 您正在將一個任意數字轉換為一個字符串,然后將其寫入緩沖區,沒有填充或任何東西? 沒有看到更多的代碼很難看到,但這肯定看起來很可疑。

通常,當具有可變長度消息時,您定義某種數據包格式,例如長度字段為4個字節(為您的消息選擇正確的字節數),然后是消息,然后您可以將(在本例中)int發送到客戶端首先讀取4個字節,然后知道從套接字讀取多少字節。 你可能想看看像htons這樣的函數。

如果你有一個可變長度標題,你可以使用某種分隔符來讀取。 這種類型的標頭在asio HTTP示例中說明,其中“\\ r \\ n \\ r \\ n”是使用的分隔符。 這個例子對你也很有用,因為在reima聲明的時候,你需要更改你的客戶端,先讀取標題,然后再讀取消息體。

您似乎正在向服務器發送請求以詢問即將到來的回復的大小,但由於TCP流本身沒有分隔符,您可能會收到大小以及部分或全部回復,同時期望僅大小! 在嘗試讀取回復的其余部分之前,您應該考慮這部分數據(顯然等待更少的字節)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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