2012-07-31 213 views
1

我已經提到過這個問題很多次,但是沒有一個解決方案似乎適用於我。我繼續發言之前,我將發佈的代碼一點點你:recv()延遲問題

// Await the response and stream it to the buffer, with a physical limit of 1024 ASCII  characters 
    stringstream input; 
    char buffer[4096*2]; 
    while (recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL) > 0) 
     input << buffer; 
    input << '\0'; 

    // Close the TCP connection 
    close(sock); 
    freehostent(hostInfo); 

這裏是我的要求:

string data; 
    { 
     stringstream bodyStream; 

     bodyStream 
      << "POST /api/translation/translate HTTP/1.1\n" 
      << "Host: elfdict.com\n" 
      << "Content-Type: application/x-www-form-urlencoded\n" 
      << "Content-Length: " << (5 + m_word.length()) 
      << "\n\nterm=" << m_word; 

     data = bodyStream.str(); 
    } 

    cout << "Sending HTTP request: " << endl << data << endl; 

我是很新的這種編程(和堆棧overflow-寧願把它撞出來,把我的頭撞在牆上,直到我自己解決問題,但我迷失了在這裏!),並真的很感激幫助解決它爲什麼需要這麼長時間!我已經考慮設置它,以便它是非阻塞的,但有問題讓它按預期工作。雖然也許這裏的人可以指出我的方向是正確的,如果非博克路線是我需要走的路。

我已經看到很多人更喜歡使用庫,但我想學會這樣做!

我也是新手,在Mac上編程和使用套接字。也許不是最好的第一次項目,但我現在開始了!所以我希望繼續:)任何幫助都會很好!

預先感謝您!

+1

你應該注意到有多少字節被讀入緩衝區,並且只寫入了很多輸入。不保證數據將包含或不包含空終止符。 – sje397 2012-07-31 11:29:00

+0

根據您的要求判斷,您正在與網絡服務器進行通信。你的請求的問題是換行符。 HTTP標準說你應該使用'「\ r \ n」'作爲換行符,而不是單個''\ n''。 – 2012-07-31 11:33:09

回答

1

的位置問題發生,因爲你指定MSG_WAITALL標誌。它會強制recv保持阻塞狀態,直到收到所有指定的字節(您的情況爲sizeof(buffer) - 1,而另一方發送的消息明顯更小),或者發生錯誤,並返回-1,並且errno變量被適當地設置。

我認爲,更好的選擇是使recv在循環中沒有任何標誌,直到另一端的套接字關閉(recv返回0)或收到一些分隔符爲止。

然而,你應該小心使用input << buffer,因爲recv可能在每次迭代只返回數據的一小部分(例如,20個字節),所以你應該把正是這個數據量,以字符串流。收到的字節數由recv返回。

2

之所以需要很長時間才能收到,是因爲您告訴系統等待,直到它已收到全部您要求的數據,即8k字節,或者連接上存在錯誤或已關閉。這是國旗MSG_WAITALL所做的。

解決此問題的一個方法是使套接字非阻塞,並在循環中進行連續讀取,直到出現錯誤或連接關閉。

如何使插座非阻塞的不同而不同的平臺,在Windows上它與ioctlsocket函數來完成,在Linux或類似的系統中,與fcntl函數來完成:

int flags = fcntl(sock, F_GETFL, 0); 
flags |= O_NONBLOCK; 
fcntl(sock, F_SETFL, flags); 

然後你從中讀取插座是這樣的:

std::istringstream input; 

for (;;) 
{ 
    char buffer[256]; 
    ssize_t recvsize; 

    recvsize = recv(sock, buffer, sizeof(buffer) - 1, 0); 
    if (recvsize == -1) 
    { 
     if (errno != EAGAIN && errno != EWOULDBLOCK) 
      break; // An error 
     else 
      continue; // No more data at the moment 
    } 
    else if (recvsize == 0) 
     break; // Connection closed 

    // Terminate buffer 
    buffer[recvsize] = '\0'; 

    // Append to input 
    input << buffer; 
} 

上述循環的問題是,如果沒有收到數據,它將永遠循環。


然而,你必須在你的代碼更加嚴重的問題:您收到到緩衝區中,然後將其追加到stringstream,但你不終止緩衝區。你不需要在流中終止字符串,它會自動完成,但你需要終止緩衝區。

這可以解決這樣的:

int rc; 
while ((rc = recv(sock, buffer, sizeof(buffer) - 1, MSG_WAITALL)) > 0) 
{ 
    buffer[rc] = '\0'; 
    input << buffer; 
}