第57章 SOCKET: UNIX DOMAIN

UNIX domain socket的地址:struct sockaddr_un
  1. struct socketaddr_un
  2. {
  3. sa_family_t sun_family: /* Always AF_UNIX */
  4. char sun_path[108]; /* Null-terminated socket pathname*/
  5. }
  6. // sun表示Socket unix

绑定UNIX domain时,bind会在文件系统中创建一个条目(因此作为socket路径名的一部分的目录需要可访问和可写),绑定的规则:

  • 无法将一个socket绑定到几个既有路径上
  • 通常会将一个socket绑定到绝对路径上,也可是相对路径,但客户端connect时需要知道该路径
  • 一个socket只能绑定到一个路径,一个路径名只能被一个socket绑定
  • 无法使用open打开一个socket
  • 当不再需要一个socket时可以使用unlink或remove删除路径条目

应该把UNIX domain socket绑定到一个公共的有安全保护措施的绝对路径上

UNIX socket中的流socket

-nothing-

UNIX socket中的数据报

对于UNIX domain socket来说,数据报的传输时在内核中发生,不仅是可靠的,而且会按顺序接收,不会重复

UNIX domain socket权限

socket文件的所有权和权限决定了哪些进程能够与这个socket进行通信,默认情况下,创建socket(通过bind)时会给所有者、组和other用户赋予所有的权限,要改变这种行为可以在调用bind前用umask禁用不希望赋予的权限

sockpair(): 创建互联socket对

有时候单个进程创建一对socket并将它们连接起来比较有用,sockpair提供了一种快捷方式:

  1. #include <sys/socket.h>
  2. int socketpair(int domain, int type, int protocol, int fd[2]);
  3. // 返回值:若成功,返回0,若出错,返回-1
  4. // domain只能指定为AF_UNIX,type可以是SOCK_DGRAM或SOCK_STREAM,protocol必须是0,fd数组返回了引用这两个互相连接的socket的文件描述符
  5. // 将type指定为SOCK_STREAM,相当于之间一个双向管道,每个socket都可以用来读写,并且这两个socket之间每个方向上的数据信道是分开的
  6. // 使用socketpair创建的一对socket不会绑定到任何地址,它们对于其他进程完全不可见
Linux抽象socket名空间

抽象路径名空间是Linux特有的,它允许将一个UNIX domain socket绑定到一个名字但不会在文件系统中创建该名字,有如下优势:

  • 无须担心与文件系统既有名称产生冲突
  • 没必要在使用完socket后删除socket路径名,socket被关闭后会自动删除这个抽象名
  • 无需为socket创建一个文件系统路径名,对于不具备文件系统写权限时比较有用

要创建一个抽象绑定,需要将sun_path字段的第一个字节指定为NULL

  1. void create_virtual_socket()
  2. {
  3. int sockfd;
  4. struct sockaddr_un addr;
  5. memset(&addr, 0x00, sizeof(struct sockaddr_un));
  6. // addr.sun_path[0] has been set to 0 by memset
  7. strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) - 2);
  8. if (-1 == (sockfd = socket(AF_UNIX, SOCK_STREAM, 0)))
  9. perror("socket error");
  10. if (-1 == bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)))
  11. perror("bind error");
  12. }