簡體   English   中英

Unix 域流套接字中數據緩沖區的大小

[英]Size of the data buffer in Unix Domain stream socket

我有一個使用 Unix 域套接字實現的客戶端和一個服務器。

我想看看客戶端可以將多少數據推送到套接字而無需服務器讀取該數據。 我希望客戶端能夠在被阻止之前發送大約 20-30KB 的數據。 我已經檢查了 net.core.rmem_default、net.core.wmem_default、net.core.rmem_max、net.core.wmem_max 和 net.unix.max_dgram_qlen sysctl 選項,我確信我沒有達到這些值。 我還增加了 net.unix.max_dgram_qlen 值,但似乎沒有幫助。

我很驚訝地看到我能夠發送的固定大小的消息數量約為 138。即使在我減少消息的大小后,這個數字仍然保持不變。

在客戶端,我進入一個循環並寫入 1024 條消息。

客戶代碼

void write_text (int socket_fd, char* text)
{
    int length = strlen (text) + 1;

    send (socket_fd, &length, sizeof (length),0);
    /* Write the string. */
    send (socket_fd, text, length,0);
}

int main (int argc, char* const argv[])
{
   const char* const socket_name = argv[1];
   char message[100];
   int socket_fd;
   int loop = 0;
   struct sockaddr_un name;
   /* Create the socket. */
   socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
   /* Store the server's name in the socket address. */
   name.sun_family = AF_UNIX;
   strcpy (name.sun_path, socket_name);
   /* Connect the socket. */
   connect (socket_fd, (struct sockaddr *) &name, SUN_LEN (&name));

   for (loop=0;loop<1024;loop++)
   {
      sprintf (message, "message number %d coming from the client", loop);
      /* Write the text on the command line to the socket. */
       write_text (socket_fd, message);
    }

    close (socket_fd);
    return 0;   
}

服務器端代碼:

unsigned int global_flag = 0;
int client_socket_fd = 0;

int server (int client_socket)
{    

  while (1) 
  {
    int length;
    char* text;

    if (read (client_socket, &length, sizeof (length)) == 0)
        return 0;

    text = (char*) malloc (length);

    read (client_socket, text, length);
    printf ("length %d %s\n", length, text);

    if (global_flag<5) break;

    free (text);
   }

    return 0;
}

int main (int argc, char* const argv[])
{
const char* const socket_name = argv[1];

int socket_fd;
struct sockaddr_un name;
int client_sent_quit_message;
socklen_t socket_length = sizeof(struct sockaddr_un);
int result;
int len = sizeof (int);
int data = 0;

socket_fd = socket (AF_LOCAL, SOCK_STREAM, 0);

name.sun_family = AF_UNIX;
strcpy (name.sun_path, socket_name);
socket_length = strlen(name.sun_path) + sizeof (name.sun_family);

bind (socket_fd, (struct sockaddr *) &name, socket_length);

listen (socket_fd, 5);

while (1)
{
        struct sockaddr_un client_name;
        socklen_t client_name_len;

        /* Accept a connection. */
        client_socket_fd = accept (socket_fd, (struct sockaddr *) &client_name, &client_name_len);

        client_sent_quit_message = server (client_socket_fd);            
}

/* Remove the socket file. */
close (socket_fd);
unlink (socket_name);
return 0;
}

在服務器端代碼 global_flag 總是小於 0,服務器因此進行一次讀取並出來。 服務器不再執行讀取操作。 客戶端同時在套接字上推送數據。

我在客戶端上做了一個 strace 並得到了這個:

VirtualBox:~/code/linux$ strace ./unix-client /tmp/unixtest

execve("./unix-client", ["./unix-client", "/tmp/unixtest"], [/* 44 vars */]) = 0
brk(0)                                  = 0x1245000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =    0x7f3e12b63000
fstat(3, {st_mode=S_IFREG|0644, st_size=68001, ...}) = 0
mmap(NULL, 68001, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3e12b52000
close(3)                                = 0

fstat(3, {st_mode=S_IFREG|0755, st_size=1815224, ...}) = 0
mmap(NULL, 3929304, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3e12583000
[clipped]
socket(PF_FILE, SOCK_STREAM, 0)         = 3
connect(3, {sa_family=AF_FILE, path="/tmp/unixtest"}, 15) = 0
sendto(3, "(\0\0\0", 4, 0, NULL, 0)     = 4
sendto(3, "message number 0 coming from the"..., 40, 0, NULL, 0) = 40
sendto(3, "(\0\0\0", 4, 0, NULL, 0)     = 4
sendto(3, "message number 1 coming from the"..., 40, 0, NULL, 0) = 40
sendto(3, "(\0\0\0", 4, 0, NULL, 0)     =  4
sendto(3, "message number 2 coming from the"..., 40, 0, NULL, 0) = 40
sendto(3, "(\0\0\0", 4, 0, NULL, 0)     = 4

..

sendto(3, "message number 138 coming from t"..., 42, 0, NULL, 0) = 42
sendto(3, "*\0\0\0", 4, 0, NULL, 0)     = 4
sendto(3, "message number 139 coming from t"..., 42, 0, NULL, 0) = 42
sendto(3, "*\0\0\0", 4, 0, NULL, 0

[和這里的客戶端塊]

知道為什么當服務器停止從套接字排出消息時客戶端在發送 139 條消息后被阻塞嗎?

我認為如果我減少消息的大小,客戶端可以在套接字上發送的消息數量會增加。 但是,我看到它保持不變。 無論消息的大小如何,客戶端都無法在套接字上發送超過 139 條消息而不會被阻塞。

您假設 read() 填充了緩沖區。 沒有指定這樣做,只傳輸至少一個字節。 您需要將返回值存儲在一個變量中,檢查它是否為 -1,檢查它是否為零,否則將其用作接收到的數據的實際長度:如果小於您的預期,請再次讀取。 沖洗並重復。

由於問題是關於在服務器不再進行讀取時調用一定數量的send()后的阻塞,因此爭論read()毫無意義。
sourcejedi 對“ Linux 可以為默認的 unix 套接字緩沖區大小使用什么值? ”問題的回答解釋說,每個數據包的開銷相當高,例如 576 字節。 雖然我們通常不考慮與面向流的套接字相關的數據包,但如果我們假設此開銷也適用於 SOCK_STREAM 類型的 UNIX 域套接字上的單個發送調用,我們可以為您的觀察得出一個解釋:默認163840 字節的緩沖區大小除以 (4+576) 字節和大約 (41+576) 字節的總和得出的數字非常接近您能夠發送的消息對的數量。

暫無
暫無

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

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