`bind()`unix域套接字客户端进程有什么用途吗?

时间:2017-12-07 20:40:25

标签: c sockets unix system

使用AF_UNIX(unix域套接字)时,是否有任何应用程序在从不调用bind()的进程中调用listen()

在我的系统编程讲座和实验室中,我们被指示在unix域套接字客户端进程上调用bind()。是否有文档化,未记录的或实用的应用程序在仅客户端 unix域套接字进程上调用bind?根据我的理解bind()创建了一个特殊的套接字文件,这是服务器进程承担的责任。这是对的吗?

以下是基于课堂讨论的概念的示例代码:

server.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

int main() {
    int s0, s1;
    struct sockaddr sa0 = {AF_UNIX, "a"};

    s0 = socket(AF_UNIX, SOCK_STREAM, 0);

    bind(s0, &sa0, sizeof(sa0) + sizeof("a"));
    listen(s0, 1);
    for (;;) {
        s1 = accept(s0, NULL, NULL);
        puts("connected!");
        for (;;) {
            char text[1];
            ssize_t n = read(s1, &text, sizeof(text));
            if (n < 1) {
                break;
            }
            putchar(text[0]);
        }
        close(s1);
    }
    close(s0);
    unlink("a");
    return 0;
}

client.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

int main() {
    int s0;
    struct sockaddr sa0 = {AF_UNIX, "b"};
    struct sockaddr sa1 = {AF_UNIX, "a"};
    socklen_t sa1_len;

    s0 = socket(AF_UNIX, SOCK_STREAM, 0);
    bind(s0, &sa0, sizeof(sa0) + sizeof("b")); // What does this do??
    connect(s0, &sa1, sizeof(sa1) + sizeof("b"));
    for (;;) {
        int c = fgetc(stdin);
        if (c == EOF) {
            break;
        }
        write(s0, &c, sizeof(c));
    }
    close(s0);
    unlink("b");
    return 0;
}

3 个答案:

答案 0 :(得分:3)

只有在需要接收bind()类型套接字的连接时才需要调用SOCK_STREAM,但bind()行为取决于SOCKET的域。有一个manual页面专用于此。

有用的信息:

  

地址格式

     

UNIX域套接字地址如下所示   结构:

#define UNIX_PATH_MAX    108

struct sockaddr_un {
    sa_family_t sun_family;               /* AF_UNIX */
    char        sun_path[UNIX_PATH_MAX];  /* pathname */
};
     

在这种结构中区分了三种类型的地址:

     
      
  • pathname:UNIX域套接字可以使用bind(2)绑定到以null结尾的文件系统路径名。当套接字的地址是   由getsockname(2),getpeername(2)和accept(2)返回,其长度   是offsetof(struct sockaddr_un,sun_path)+ strlen(sun_path)+ 1,和   sun_path包含以null结尾的路径名。

  •   
  • unnamed:未使用bind(2)绑定到路径名的流套接字没有名称。同样,由两个套接字创建   socketpair(2)未命名。当未命名的套接字的地址是   由getsockname(2),getpeername(2)和accept(2)返回,其长度   是sizeof(sa_family_t),不应检查sun_path。

  •   
  • abstract:抽象套接字地址的区别在于sun_path [0]是一个空字节('\ 0')。套接字的地址在此   命名空间由sun_path中的附加字节给出   由指定长度的地址结构覆盖。 (空字节   在名称中没有特别的意义。)名称没有联系   使用文件系统路径名。当抽象套接字的地址是   由getsockname(2),getpeername(2)和accept(2)返回   返回的addrlen大于sizeof(sa_family_t)(即更大   而2),套接字的名称包含在第一个(addrlen

  •   
  • sizeof(sa_family_t))sun_path的字节。抽象套接字命名空间是一个不可移植的Linux扩展。
  •   
  

使用文件名绑定到套接字会在文件中创建套接字   系统必须在不再需要时由调用者删除   (使用unlink(2))。通常的UNIX封闭语义适用;该   套接字可以随时取消链接,最终将被删除   最后一次引用它时的文件系统。

所以:

  • bind()在客户端不是必需的。
  • 您的上下文中的
  • bind()会为您的套接字"a""b"
  • 命名
  • bind(s0, &sa0, sizeof(sa0) + sizeof("b"));和您的代码中的类似行是未定义的行为;它给bind()的大小超出了&sa0的范围。正确的代码是bind(s0, &sa0, sizeof sa0);
  • 在此上下文中,
  • bind()(Linux,AF_UNIX)确实创建了一个特殊的套接字文件;如果您要将其删除,则必须致电unlink()remove()

答案 1 :(得分:1)

man bind给出了这个答案:

   When  a  socket  is  created  with socket(2), it exists in a name space
   (address family) but has no address assigned to it.  bind() assigns the
   address  specified  by  addr  to  the  socket  referred  to by the file
   descriptor sockfd.  addrlen  specifies  the  size,  in  bytes,  of  the
   address structure pointed to by addr.  Traditionally, this operation is
   called “assigning a name to a socket”.

   It is normally necessary to assign a local address using bind()  before
   a SOCK_STREAM socket may receive connections (see accept(2)).

答案 2 :(得分:1)

在Unix域套接字上调用bind(),无意调用accept(),这是确保只有一个进程副本正在运行的非常有用的方法。它比依赖进程名称更强大,因为二进制文件可以复制并以其他名称运行。

异常终止(SIGSEGV,作为kill -9 ...的目标)的清理是一个问题。因为除非你的应用程序在信号处理程序中执行它,否则不会删除套接字。