以下内容引述至《Linux/Unix系统编程手册》
Unix domain socket允许同一系统上不同进程之间相互通信的一种方式
在Unix domain中,socket地址以路径名来表示,domain特定的socket地址结构的定义如下所示:
struct socketaddr_un {
sa_family_t sum_family;
char sun_path[108];
}
sockaddr_un 结构中字段 sun_前缀是根据socket unix而来。sun_path字段长度是108字节或104字节,现代使用94字节。可移植应用程序在编码时应该采用最低值,并且在向这个字段写入数据时使用snprintf()或strncpy()以避免缓冲区溢出。
当用来绑定Unix domain socket时,bind会在文件系统中创建一个条目。文件的所有权将根据常规的文件创建规则来确定。这个文件会被标志为一个socket
有关绑定一个Unix domain socket方面还需要注意一下几点:
现实世界中的应用程序应该将Unix domain socket bind()到一个采取了恰当的安全保护措施的目录中的绝对路径名上。
服务器程序执行任务:
客户端程序执行任务:
Unix domain socket传输的数据报的最大大小并没有规定。在Linux上可以发送一个相当大的数据报,其限制是通过SO_SNDBUF socket选项和各个/proc文件来控制的。
服务器程序首先创建一个socket并将其绑定到一个众所周知的地址上,然后进入一个无限循环,在循环中使用recvfrom()接收来自客户端的数据报,将接收到的文件转换成大小格式并使用通过recvfrom()获取的地址将转换过的文本返回给客户端
客户端创建一个socket并将这个socket绑定到一个地址上,这样服务器就能够发送响应了。客户端地址的唯一性是通过路径名包含客户端的进程ID来保证的,然后客户端循环,将所有命令行参数作为一个个独立的消息发送给服务器。在发送完每条消息之后,客户端读取服务器的相应并将内容显示在标准输出上。
socket文件的所有权和权限决定了哪些进程能够与这个socket进行通信
有时候让单个进程创建一对socket并将它们连接起来是比较有用的。这可以通过使用两个socket()调用和一个bind()调用以及对listen()、connect()、accept()(用于流socket)的调用或对connect()(用于数据报socket)的调用来完成。
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sockfd[2]);
socketpair系统调用只能用在Unix domain中,即domain参数必须被指定为AF_UNIX
socket的type可以被指定为SOCK_DGRAM或SOCK_STREAM
protocol参数必须为0, sockfd数据返回了引用这两个相互连接的socket的文件描述符
将type指定为SOCK_STREAM相对于创建一个双向管道(也被称为流管道),每个socket都可以用来读取和写入,并且这两个socket之间每个方向上的数据信道是分开的。
一般来讲,socket对的使用方式与管道的使用方式类似,调用完socketpair()后,进程会使用fork()创建一个子进程。子进程会继承父进程的文件描述符的副本,包括引用socket对的描述符。因此父进程和子进程就可以使用这一对socket来进行IPC了
所谓的抽象路径名空间是Linux特有的一项特性,它允许将一个Unix domain socket绑定到一个名字上但不会在文件系统中创建该名字,优势是:
要创建一个抽象绑定就需要将sum_path字段的第一个字节指为NULL字节(\0)
这样就能够将抽象socket名字与传统UNIX domain socket路径名区分开来。