Unix域流套接字中数据缓冲区的大小

问题描述 投票:3回答:2

我有一个使用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,因此服务器执行一次读取并输出。服务器不再进行任何读取。同时客户端正在将数据推送到套接字上。

我对客户端进行了跟踪,并得到了:

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条消息而不会被阻塞。

c linux sockets unix
2个回答
2
投票

您假设read()填充了缓冲区。没有指定这样做,仅传输至少一个字节。您需要将返回值存储在变量中,将其检查为-1,将其检查为零,否则将其用作接收到的数据的实际长度:如果该长度小于您的预期,请重新读取。冲洗并重复。


0
投票

由于问题是关于服务器不再完成读取操作时,在一定数量的send()调用之后进行阻塞,因此争论read()毫无意义。sourcejedi对问题[What values may Linux use for the default unix socket buffer size?]的回答说明,e的开销相当大。 G。 576字节每个数据包。尽管我们通常不会考虑与面向流的套接字相关的数据包,但是如果我们假设此开销也适用于SOCK_STREAM类型的UNIX域套接字上的单个发送调用,则可以为您的观察提供一个解释。缓冲区大小163840字节除以(4 + 576)字节与大约(41 + 576)字节的总和,得出的数字非常接近您能够发送的消息对的数量。

© www.soinside.com 2019 - 2024. All rights reserved.