2012-06-05 48 views
19

我看到一對夫婦奇怪的東西有一對通過調用創建如AF_UNIX插座:AF_UNIX套接字開銷?

socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

凡SFD是一個i​​nt [2]數組的文件描述符。

首先,默認緩衝區大小似乎完全是122K(124928字節),而不是來自/ proc/sys/net的任何內容(例如wmem_default設置爲128K)。有誰知道這個奇怪的緩衝區大小的原因?

其次,通過套接字(8字節)寫小信息時。我只能在寫入塊之前寫入其中的423個,它只有8 * 423 = 3384個字節,是另一個奇怪的大小。這些消息的行爲好像它們每個都佔用了295+個小字節。這種開銷的來源是什麼?

運行在RHEL6(2.6.32,64位)

我寫了一個程序來嘗試不同的數據大小,以比較間接成本:

#include <errno.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

#define DATA_SIZE 4 

void run(size_t size) { 
    int sfd[2]; 
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { 
     perror("error"); 
    } 


    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Data Size: %zd\n", size); 
    char buff[size]; 
    size_t wrote=0; 
    for (size_t ii=0; ii < 32768; ii++) { 
     if ((send(sfd[0], buff, size, MSG_DONTWAIT) == -1) && (errno == EAGAIN)) { 
      wrote = ii; 
      break; 
     } 
    } 

    printf("Wrote:  %zd\n", wrote); 

    if (wrote != 0) { 
     int bpm = sndbuf/wrote; 
     int oh = bpm - size; 

     printf("Bytes/msg: %i\n", bpm); 
     printf("Overhead: %i\n", oh); 
     printf("\n"); 
    } 

    close(sfd[0]); close(sfd[1]); 
} 

int main() { 
    int sfd[2]; 
    socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Buffer Size: %i\n\n", sndbuf); 
    close(sfd[0]); close(sfd[1]); 

    for (size_t ii=4; ii <= 4096; ii *= 2) { 
     run(ii); 
    } 
} 

其中給出:

Buffer Size: 124928 

Data Size: 4 
Wrote:  423 
Bytes/msg: 295 
Overhead: 291 

Data Size: 8 
Wrote:  423 
Bytes/msg: 295 
Overhead: 287 

Data Size: 16 
Wrote:  423 
Bytes/msg: 295 
Overhead: 279 

Data Size: 32 
Wrote:  423 
Bytes/msg: 295 
Overhead: 263 

Data Size: 64 
Wrote:  423 
Bytes/msg: 295 
Overhead: 231 

Data Size: 128 
Wrote:  348 
Bytes/msg: 358 
Overhead: 230 

Data Size: 256 
Wrote:  256 
Bytes/msg: 488 
Overhead: 232 

Data Size: 512 
Wrote:  168 
Bytes/msg: 743 
Overhead: 231 

Data Size: 1024 
Wrote:  100 
Bytes/msg: 1249 
Overhead: 225 

Data Size: 2048 
Wrote:  55 
Bytes/msg: 2271 
Overhead: 223 

Data Size: 4096 
Wrote:  29 
Bytes/msg: 4307 
Overhead: 211 

與使用管道相比,絕對有很多開銷:

Data Size: 4 
Wrote:  16384 
Bytes/msg: 4 
Overhead: 0 

Data Size: 8 
Wrote:  8192 
Bytes/msg: 8 
Overhead: 0 

Data Size: 16 
Wrote:  4096 
Bytes/msg: 16 
Overhead: 0 

Data Size: 32 
Wrote:  2048 
Bytes/msg: 32 
Overhead: 0 

Data Size: 64 
Wrote:  1024 
Bytes/msg: 64 
Overhead: 0 

Data Size: 128 
Wrote:  512 
Bytes/msg: 128 
Overhead: 0 

Data Size: 256 
Wrote:  256 
Bytes/msg: 256 
Overhead: 0 

Data Size: 512 
Wrote:  128 
Bytes/msg: 512 
Overhead: 0 

Data Size: 1024 
Wrote:  64 
Bytes/msg: 1024 
Overhead: 0 

Data Size: 2048 
Wrote:  32 
Bytes/msg: 2048 
Overhead: 0 

Data Size: 4096 
Wrote:  16 
Bytes/msg: 4096 
Overhead: 0 
+0

send()返回實際寫入的字節數。你應該總結這些,而不是假設它全部寫成。 – EJP

+1

最糟糕的情況我寫的東西比我聲稱的要少,這會讓域套接字的開銷更糟。 –

回答

1

你看了看sysctl的net.unix.max_dgram_qlen的值嗎?

內核對正在傳輸的AF_UNIX數據報的最大數量施加了限制。 在我的系統上,限制實際上是非常低的:只有10.

+0

我不知道,沒有。這是否適用於此,因爲我使用SOCK_STREAM類型? –

+1

不,這應該只適用於數據報套接字,至少在我看的內核版本。 –

+1

事實上,我不明白爲什麼一個unix數據報套接字寫入會在短時間內擊中wmem_max。 –

5

查看socket(7)手冊頁。有一段內容如下:

SO_SNDBUF 設置或獲取以字節爲單位的最大套接字發送緩衝區。當使用setsockopt(2)設置內核時,內核將此值加倍 (以允許用於簿記開銷的空間),並且getsockopt(2)返回此 加倍的值。默認值由 /proc/sys/net/core/wmem_default文件設置,最大允許值由 /proc/sys/net/core/wmem_max文件設置。此選項的最小值(加倍)爲 2048.

因此看起來開銷僅僅是爲內核保存簿記信息。

+0

我甚至不能確定適用於當地的插座,以及可用的緩衝空間的簡單減半還是不會考慮所有我看到的開銷。所以我假設它適用全線 –

+1

手冊頁不AF_UNIX或者非本地域進行區分。這就是我所能找到的關於情況的所有文檔。我想,如果你需要知道「究竟」是什麼開銷用於你將不得不看看內核的網絡代碼。 – Chimera

+1

我沒有接受這個答案,因爲我覺得即使因子的兩開銷,我仍然看到每封郵件的方式太多了。即使內核只讓我用62464個字節,那麼我應該能夠填充緩衝區之前寫15000+郵件,我只能看見那1/30。 –