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

时间:2014-08-20 13:50:57

标签: c linux sockets unix

我有一个使用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条消息而不会被阻止。

2 个答案:

答案 0 :(得分:1)

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

答案 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)字节的总和,得出的数字非常接近您能够发送的消息对的数量。