簡體   English   中英

Windows中套接字發送緩沖區的大小是多少?

[英]What is the size of a socket send buffer in Windows?

根據我的理解,每個套接字都與兩個緩沖區,一個發送緩沖區和一個接收緩沖區相關聯,所以當我調用send()函數時,發生的事情是要發送的數據將放入發送緩沖區,它是Windows現在負責將此發送緩沖區的內容發送到另一端。

在阻塞套接字中, send()函數在提供給它的整個數據放入發送緩沖區之前不會返回。

那么發送緩沖區的大小是多少?

我執行了以下測試(發送1 GB的數據):

#include <stdio.h>

#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#include <Windows.h>

int main()
{
    // Initialize Winsock
    WSADATA wsa;
    WSAStartup(MAKEWORD(2, 2), &wsa);

    // Create socket
    SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

    //----------------------

    // Connect to 192.168.1.7:12345
    sockaddr_in address;
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("192.168.1.7");
    address.sin_port = htons(12345);
    connect(s, (sockaddr*)&address, sizeof(address));

    //----------------------

    // Create 1 GB buffer ("AAAAAA...A")
    char *buffer = new char[1073741824];
    memset(buffer, 0x41, 1073741824);

    // Send buffer
    int i = send(s, buffer, 1073741824, 0);

    printf("send() has returned\nReturn value: %d\nWSAGetLastError(): %d\n", i, WSAGetLastError());

    //----------------------

    getchar();
    return 0;
}

輸出:

send() has returned
Return value: 1073741824
WSAGetLastError(): 0

send()已立即返回,這是否意味着發送緩沖區的大小至少為1 GB?

這是關於測試的一些信息:

  • 我正在使用TCP阻塞套接字。
  • 我已連接到局域網機器。
  • 客戶端Windows版本:Windows 7旗艦版64位。
  • 服務器Windows版本:Windows XP SP2 32位(安裝在Virtual Box上)。

編輯:我也嘗試連接到谷歌(173.194.116.18:80),我得到了相同的結果。

編輯2:我發現了一些奇怪的事情,將發送緩沖區設置為64 KB到130 KB之間的值將使send()按預期工作!

int send_buffer = 64 * 1024;    // 64 KB
int send_buffer_sizeof = sizeof(int);
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)send_buffer, send_buffer_sizeof);

編輯3:事實證明(感謝Harry Johnston)我以不正確的方式使用了setsockopt() ,這是它的使用方式:

setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&send_buffer, send_buffer_sizeof);

將發送緩沖區設置為64 KB和130 KB之間的值不會使send()按預期工作, 而是將發送緩沖區設置為0使其阻塞(這是我注意到的,無論如何,我沒有任何文檔這個行為)。

所以現在我的問題是:我在哪里可以找到有關send() (以及其他套接字操作)如何在Windows下工作的文檔?

在調查了這個問題之后。 這就是我認為正確的答案:

調用send() ,可能會發生兩件事:

  • 如果有待處理的數據低於SO_SNDBUF ,則send()將立即返回(無論您是發送5 KB還是發送500 MB都無關緊要)。

  • 如果有待處理的數據高於或等於SO_SNDBUF ,則send()將阻塞,直到發送了足夠的數據將待處理數據恢復到SO_SNDBUF以下。

請注意,此行為僅適用於Windows套接字,而不適用於POSIX套接字。 我認為POSIX套接字只使用一個固定大小的發送緩沖區(如果我錯了,請糾正我)。


現在回到主要問題“Windows中套接字發送緩沖區的大小是多少?”。 我想如果你有足夠的內存,如果有必要可以超過1 GB(不知道最大限制是多少)。

我可以重現這種行為,並且使用資源監視器很容易看到Windows在發生send()時確實分配了1GB的緩沖區空間。

一個有趣的功能是,如果您在第一個發送后立即執行第二次發送,則在兩個發送完成之前,該呼叫不會返回。 發送完成后,第一次發送的緩沖區空間將被釋放,但第二次send()將繼續阻塞,直到所有數據都已傳輸完畢。

我懷疑行為的不同是因為第一次發送完成后第二次調用send()已經阻塞了。 send()的第三次調用立即返回(並且分配了1GB的緩沖區空間),就像第一次調用一樣,依此類推,交替進行。

所以我得出結論,問題的答案(“發送緩沖區有多大?”)是“與Windows認為合適的大”。 結果是,為了避免耗盡系統內存,你應該將阻塞發送限制在不超過幾百兆字節。

你對setsockopt()的調用是不正確的; 第四個參數應該是一個指向整數的指針,而不是一個轉換為指針的整數。 一旦糾正,事實證明將緩沖區大小設置為零會導致send()始終阻塞。

總而言之,觀察到的行為是send()將立即返回提供:

  • 有足夠的內存來緩沖所有提供的數據
  • 沒有發送已經在進行中
  • 緩沖區大小未設置為零

否則,它將在數據發送后返回。

KB214397描述了一些 - 感謝漢斯! 特別是它描述了將緩沖區大小設置為零會禁用Winsock緩沖,並且注釋“如果需要,Winsock可以緩沖超過SO_SNDBUF緩沖區大小”。

(描述的完成通知與觀察到的行為不完全匹配,這取決於我猜你如何解釋“先前緩沖的發送”。但它已經接近了。)

請注意,除了無意中耗盡系統內存的風險之外,這一切都不重要。 如果你真的需要知道另一端的代碼是否已經收到了你的所有數據,那么唯一可行的方法就是讓它告訴你。

在阻塞套接字中,send()函數在提供給它的整個數據放入發送緩沖區之前不會返回。

這不能保證。 如果有可用的緩沖區空間,但沒有足夠的空間容納整個數據,那么套接字可以(並且通常會)接受它可以接收的任何數據而忽略其余的數據。 send()的返回值告訴您實際接受了多少字節。 您必須再次調用send()來發送剩余數據。

那么發送緩沖區的大小是多少?

使用帶有SO_SNDBUF選項的getsockopt()來查找。

使用帶有SO_SNDBUF選項的setsockopt()來指定您自己的緩沖區大小。 但是,套接字可能會對您指定的值施加最大上限。 使用getsockopt()來找出實際分配的大小。

暫無
暫無

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

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