Unxi域套接字并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API就是在不同主机上执行客户/服务器通信所用的API。可以视为IPC方法之一。
UNix域提供两类套接字: 字节流套接字(类似TCP) , 数据报套接字(类似UDP)
使用Unix域套接字有以下三个理由:
1、Unix域套接字往往比通信两端位于同一主机的TCP套接字快出一倍。X Window System发挥了Unix域套接字的这个优势。当一个X11客户打开到一个X11服务器的连接时,该客户检查DISPLAY环境变量的值(其中指定服务器的主机名,窗口和屏幕)。如果服务器和客户处于同一主机,客户就打开一个到服务器的Unix域套接字字节流连接,否则打开一个到服务器的TCP连接。
2、 Unix域套接字可用于在同一主机上的不同进程之间传递描述符
3、unix域套接字较新的实现把客户的凭证提供给服务器,从而能提供额外的安全检查措施。
Unix域中用于标识客户和服务器的协议地址是普通文件系统中的路径名。
Unix域套接字地址结构
下面给出一个例子,Unix域的套接字的bind调用
以下为结果
如果我们没有使用unlink,那么在文件已存在条件下重复上述指令:
使用Unix域套接字的一些规则或要求:
1、由bind创建的路径名默认访问权限为0777,之后由umask修正
2、路径名应该是一个绝对路径名
3、在connect调用中指定的路径名必须是一个当前绑定在某个打开的Unix域套接字上的路径名,套接字类型必须一致(流还是数据包必须一致)
4、调用connect连接一个Unix域套接字涉及的权限测试等同与调用open以只写的方式访问相应路径名
5、UNix域字节流套接字类似TCP套接字,他们都为进程提供一个无记录边界的字节流接口
6、如果对于某个UNix域字节流套接字的connect调用发现这个监听套接字的队列已满,调用立即返回一个ECONNREFUSED错误。对于TCP来说,并不会返回错误,而是忽略新来的请求,迫使发送端发送多次SYN进行重试
7、Unix域数据报套接字类似UDP套接字,都提供一个保留记录边界的不可靠的数据报服务
8、在一个未绑定的Unix域套接字上发送数据报不会自动给这个套接字捆绑一个路径名,这一点不同于UDP套接字:在一个未绑定的UDP套接字上发送UDP数据报导致给这个套接字捆绑一个临时端口。这就意味着除非数据报发送端已经捆绑一个路径名到它的套接字,否则数据报接收端无法发回应答数据报。
类似的,对于某个Unix域数据报套接字的connect调用不会给本套接字捆绑一个路径名,这里不同于UDP/TCP
Unix域字节流客户/服务器程序
Unix域数据报客户/服务器
传递描述符
通常,父进程可以简单的把描述符传递给子进程,子进程却不是那么容易。
这里提供了一种方法,使得两个即使毫不相关的进程也可以传递描述符。
步骤 如下:
1、创建一个字节流或数据报的Unix域套接字
如果是子进程想把打开的描述符传递给父进程,那么父进程可以预先调用socketpair函数创建一个可用于在父子进程之间交换描述符的流管道
如果进程之间没有关系,那么服务器进程必须创建一个UNix域字节流套接字,bind一个路径到该套接字,以允许客户进程connect到该套接字。然后客户可以向服务器发送一个打开某个描述符的请求,服务器在把该描述符通过Unix域套接字传递回客户。客户和服务器之间也可以用Unix域数据报套接字,但没什么好处还可能丢失
2、进程之间传递的描述符不限类型,可以是发送进程任一Unix函数打开的一个描述符,比如open,pipe,mkfifo,socket,accept等,因此我们称这种技术为描述符传递而不是文件描述符传递原因
3、发送进程构建一个msghdr结构,作为辅助数据发送。发送进程调用sendmsg发送该描述符。一旦调用sendmsg,我们就称这个描述符“在飞行中”,因为这个操作会使该描述符的引用计数加一,所以即使在调用sendmsg发送之后,立即关闭该描述符,这个描述符依旧是处于打开状态的。
4、接收进程调用recvfrom接收这个描述符,这个描述符与发送进程中描述符指向内核中相同的文件表项。
要注意的是,接收进程需要早先知道何时期待接收,如果接收进程调用recvfrom时没有分配用于接收描述符的空间,那么早先传来的描述符就作废了。
另外,recvfrom中尽量避免MSG_PEEK,否则后果不可预料。
下面就给出传递描述符的例子:
程序名为 mycat(即类cat程序),通过命令行参数获取一个路径名,打开文件并复制到标准输出。
程序调用 my_open函数,不是系统自带open函数
my_open创建一个流管道,并调用fork和exec启动执行另一个程序,期待输出的文件由这个程序打开。该程序随后必须把打开的描述符通过流管道传递回父进程。
注意,上述程序里的read_fd和write_fd都没有提供具体的实现。
总结:
与IPC其他方法相比,UNix域套接字的优势体现在其API几乎等同于网络客户/服务器API。
在把UDP客户端修改为Unix域套接字数据报客户端的显著区别是, 必须bind一个路径名到数据报客户套接字 ,以使服务器有发送应答的目的
UNix域提供两类套接字: 字节流套接字(类似TCP) , 数据报套接字(类似UDP)
使用Unix域套接字有以下三个理由:
1、Unix域套接字往往比通信两端位于同一主机的TCP套接字快出一倍。X Window System发挥了Unix域套接字的这个优势。当一个X11客户打开到一个X11服务器的连接时,该客户检查DISPLAY环境变量的值(其中指定服务器的主机名,窗口和屏幕)。如果服务器和客户处于同一主机,客户就打开一个到服务器的Unix域套接字字节流连接,否则打开一个到服务器的TCP连接。
2、 Unix域套接字可用于在同一主机上的不同进程之间传递描述符
3、unix域套接字较新的实现把客户的凭证提供给服务器,从而能提供额外的安全检查措施。
Unix域中用于标识客户和服务器的协议地址是普通文件系统中的路径名。
Unix域套接字地址结构
下面给出一个例子,Unix域的套接字的bind调用
以下为结果
如果我们没有使用unlink,那么在文件已存在条件下重复上述指令:
使用Unix域套接字的一些规则或要求:
1、由bind创建的路径名默认访问权限为0777,之后由umask修正
2、路径名应该是一个绝对路径名
3、在connect调用中指定的路径名必须是一个当前绑定在某个打开的Unix域套接字上的路径名,套接字类型必须一致(流还是数据包必须一致)
4、调用connect连接一个Unix域套接字涉及的权限测试等同与调用open以只写的方式访问相应路径名
5、UNix域字节流套接字类似TCP套接字,他们都为进程提供一个无记录边界的字节流接口
6、如果对于某个UNix域字节流套接字的connect调用发现这个监听套接字的队列已满,调用立即返回一个ECONNREFUSED错误。对于TCP来说,并不会返回错误,而是忽略新来的请求,迫使发送端发送多次SYN进行重试
7、Unix域数据报套接字类似UDP套接字,都提供一个保留记录边界的不可靠的数据报服务
8、在一个未绑定的Unix域套接字上发送数据报不会自动给这个套接字捆绑一个路径名,这一点不同于UDP套接字:在一个未绑定的UDP套接字上发送UDP数据报导致给这个套接字捆绑一个临时端口。这就意味着除非数据报发送端已经捆绑一个路径名到它的套接字,否则数据报接收端无法发回应答数据报。
类似的,对于某个Unix域数据报套接字的connect调用不会给本套接字捆绑一个路径名,这里不同于UDP/TCP
Unix域字节流客户/服务器程序
Unix域数据报客户/服务器
传递描述符
通常,父进程可以简单的把描述符传递给子进程,子进程却不是那么容易。
这里提供了一种方法,使得两个即使毫不相关的进程也可以传递描述符。
步骤 如下:
1、创建一个字节流或数据报的Unix域套接字
如果是子进程想把打开的描述符传递给父进程,那么父进程可以预先调用socketpair函数创建一个可用于在父子进程之间交换描述符的流管道
如果进程之间没有关系,那么服务器进程必须创建一个UNix域字节流套接字,bind一个路径到该套接字,以允许客户进程connect到该套接字。然后客户可以向服务器发送一个打开某个描述符的请求,服务器在把该描述符通过Unix域套接字传递回客户。客户和服务器之间也可以用Unix域数据报套接字,但没什么好处还可能丢失
2、进程之间传递的描述符不限类型,可以是发送进程任一Unix函数打开的一个描述符,比如open,pipe,mkfifo,socket,accept等,因此我们称这种技术为描述符传递而不是文件描述符传递原因
3、发送进程构建一个msghdr结构,作为辅助数据发送。发送进程调用sendmsg发送该描述符。一旦调用sendmsg,我们就称这个描述符“在飞行中”,因为这个操作会使该描述符的引用计数加一,所以即使在调用sendmsg发送之后,立即关闭该描述符,这个描述符依旧是处于打开状态的。
4、接收进程调用recvfrom接收这个描述符,这个描述符与发送进程中描述符指向内核中相同的文件表项。
要注意的是,接收进程需要早先知道何时期待接收,如果接收进程调用recvfrom时没有分配用于接收描述符的空间,那么早先传来的描述符就作废了。
另外,recvfrom中尽量避免MSG_PEEK,否则后果不可预料。
下面就给出传递描述符的例子:
程序名为 mycat(即类cat程序),通过命令行参数获取一个路径名,打开文件并复制到标准输出。
程序调用 my_open函数,不是系统自带open函数
my_open创建一个流管道,并调用fork和exec启动执行另一个程序,期待输出的文件由这个程序打开。该程序随后必须把打开的描述符通过流管道传递回父进程。
注意,上述程序里的read_fd和write_fd都没有提供具体的实现。
总结:
与IPC其他方法相比,UNix域套接字的优势体现在其API几乎等同于网络客户/服务器API。
在把UDP客户端修改为Unix域套接字数据报客户端的显著区别是, 必须bind一个路径名到数据报客户套接字 ,以使服务器有发送应答的目的