2009-06-15 143 views
1

儘管send()在大部分時間發送所有數據時都成功,但情況並非總是如此。因此建議人們使用write-fdset作爲select()和poll()來檢查套接字何時可寫。如何緩衝send()和select()的數據?

通常的機制是如何實際緩衝數據發送,同時仍然保持一個很好理解的源代碼?

+0

這不是一個更多的POSIX/UNIX C庫相關的問題,而不是一個C++問題?你可能想要重播它。 – 2009-06-15 21:20:00

回答

1

正如我們在C++中的土地,你可以將數據存儲在一個std :: vector的

新的數據被追加到向量的末尾。當您收到套接字可寫的通知時,請嘗試發送完整的向量。 send()將返回實際發送的數量。然後,只需從矢量的開始處刪除該字節數:

std::vector<char> buffer; 
... 
if(! buffer.empty()) 
{ 
    int bytesRead = send(socket, &buffer[ 0 ], buffer.size(), flags); 
    if(bytesRead > 0) 
     buffer.erase(0, bytesRead); 
    else 
     // some error... 
} 

因此可能需要更多錯誤檢查,但您明白了嗎?

對每個單獨的發送請求進行排隊,這裏的優點是假設您使用TCP,您可能會將多個更高級別的發送組合成一個套接字發送。

但是,Remus正確地提到,您的流量控制和API是棘手的問題 - 即如何阻止緩衝區變得過大?

+0

這是一個很好的例子,雖然我的第一個挑剔就是當你擦除頭部時你不必要地複製了向量的尾部 - 我會在這裏使用某種循環緩衝區,第二個挑戰是該向量不釋放內存時它的大小發生變化,你必須手動完成。 – 2009-06-16 18:23:48

1

我對socket編程的* nix一點也不是很熟悉,但是我在Win32端遇到了同樣的問題。緩衝並不是什麼大問題(你排隊請求,窺視寫入完成後從隊列中提交),真正的問題是需要緩衝實際處理流量控制的信號,並且無法解析流量控制單獨緩衝:消費者總是比生產者慢,緩衝區基本上會失去控制。您必須將流控制向上傳播到任何正在生成數據的模塊,並且這會生成非常複雜的接口。所有'寫入'請求都必須支持指示流量控制狀態(即'停止寫入,沒有更多空間!')的返回代碼以及邀請調用者恢復寫入操作的回調。

1

在編寫需要圍繞select()/ poll()循環的OO時,需要一個很好的抽象。我一直髮現自適應通信環境(ACE)反應堆類非常適合這一點。 Doug Schmidt有一些書籍「C++ Network Programming」涵蓋了這個環境,還包括網絡上的其他各種東西,包括The Design and Use of the ACE Reactor