写点什么

网络协议之:socket 协议详解之 Unix domain Socket

作者:程序那些事
  • 2022 年 3 月 16 日
  • 本文字数:2864 字

    阅读完需:约 9 分钟

网络协议之:socket协议详解之Unix domain Socket

简介

之前的文章我们讲到了 Socket 中的 Stream Socket 和 Datagram Socket,这两种 Socket 通常分别是基于 tcp 和 udp 协议来进行数据的传输。这两种 Socket 都有一个共同的特点,那就是需要一个 IP 地址和端口来建立客户端和服务器端的连接。


那么今天我们会来讲解一个特殊的 socket,这个 socket 不需要使用传统的 IP 地址和端口,而是使用文件系统来进行程序之间的数据交互,并且这样的 socket 只能使用在 unix 系统上。这样的 socket 就是今天我们要讲解的 Unix domain Socket。

什么是 Unix domain Socket

什么是 Unix domain Socket 呢? 我们从名字就可以看出来,这个 Socket 是和 unix domain 有关系的,也就是说这个 socket 需要用到 unix 下面的一些特殊功能。


我们考虑下常用的 windows 系统和 unix 系统,他们最大的区别在哪里呢?


其实最大的区别就是 unix 操作系统中一切都可以看做是文件,包括程序运行的一些信息。


那么我们是不是可以直接借助于这些程序运行时产生的文件来进行不同程序之间数据的交互呢?答案是肯定的。这就是我们今天要讨论的 Unix domain Socket。


Unix domain Socket 可以简称为 UDS,不同程序间的数据可以在操作系统层,借助于文件系统来进行数据交换。


对于程序本身来说,只需要读取和写入共享的 socket 文件即可,也就是说不同的程序之间通过 socket 文件来进行数据交互。


和基于 IP 和端口的 Socket 一样,Unix domain Socket 也可以分为 Stream Socket 和 Datagram Socket。


我们最多看到 Unix domain socket 的地方可能就是 docker 了,作为一种容器技术,docker 需要和实体机进行快速的数据传输和信息交换,一般情况下 UDS 的文件是以.socket 结尾的,我们可以在/var/run 目录下面使用下面的命令来查找:


find . -name "*.sock"
复制代码


如果你有 docker 在运行的话,可以得到下面的结果:


./docker.sock./docker/libnetwork/6d66a24bfbbfa231a668da4f1ed543844a0514e4db3a1f7d8001a04a817b91fb.sock./docker/libcontainerd/docker-containerd.sock
复制代码


可以看到 docker 是通过上面的 3 个 sock 文件来进行通讯的。

使用 socat 来创建 Unix Domain Sockets

之前提到了 socat 这个万能的工具,不仅可以创建 tcp 的监听服务器,还能创建 udp 的监听服务器,当然对于 UDS 来说也不在话下。我们来看下使用 socat 来创建 UDS 服务器所需要用到的参数:


      unix-listen:<filename>    groups=FD,SOCKET,NAMED,LISTEN,CHILD,RETRY,UNIX      unix-recvfrom:<filename>  groups=FD,SOCKET,NAMED,CHILD,RETRY,UNIX
复制代码


这里我们要使用到 unix-listen 和 unix-recvfrom 这两个参数,unix-listen 表示的是创建 stream-based UDS 服务,而 unix-recvfrom 表示的是创建 datagram-based UDS。


可以看到两个参数后面都需要传入一个文件名,表示 UDS socket 的地址。


我们可以这样使用:


socat unix-listen:/tmp/stream.sock,fork /dev/null&socat unix-recvfrom:/tmp/datagram.sock,fork /dev/null&
复制代码


这里我们使用/tmp/datagram.sock 来表示这个 socket 信息。


其中 fork 参数表示程序在接收到程序包之后继续运行,如果不用 fork,那么程序会自动退出。


socat 后面本来要接一个 bi-address,这里我们使用/dev/null,表示丢弃掉所有的 income 信息。


运行后我们可能得到下面的结果:


[1] 27442[2] 27450
复制代码


表示程序已经成功执行了,返回的是程序的 pid。

使用 ss 命令来查看 Unix domain Socket

在使用 ss 命令之前,我们先来看下使用 socat 生成的两个文件:


srwxrwxr-x   1 flydean flydean    0 Mar  2 21:58 stream.socksrwxrwxr-x   1 flydean flydean    0 Mar  2 21:59 datagram.sock
复制代码


可以看到这两个文件的权限,rwx 大家都懂,分别是 read,write 和执行权限。那么最前面的 s 是什么呢?


最前面的一位表示的是文件类型,s 表示的就是 socket 文件。


扩展一下,这个位置还可以有其他几种选项:p、d、l、s、c、b 和-:


其中 p 表示命名管道文件,d 表示目录文件,l 表示符号连接文件,-表示普通文件,s 表示 socket 文件,c 表示字符设备文件,b 表示块设备文件。


接下来我们使用 ss 命令来查看一下之前建立的 UDS 服务。


这里需要使用到下面几个参数:


   -n, --numeric       don't resolve service names   -l, --listening     display listening sockets   -x, --unix          display only Unix domain sockets
复制代码


这里我们需要使用到上面 3 个选项,x 表示的是显示 UDS,因为是监听,所以使用-l 参数,最后我们希望看到具体的数字,而不是被解析成了服务名,所以这里使用-n 参数。


我们可以尝试执行一下下面的命令:


ss -xln
复制代码


输出会很多,我们可以 grep 我们需要的 socket 如下所示:


ss -xln | grep tmpu_str  LISTEN     0      5      /tmp/stream.sock 11881005              * 0                  u_dgr  UNCONN     0      0      /tmp/datagram.sock 11882190              * 0  
复制代码


u_str 表示的是 UDS stream socket,而 u_dg 表示的是 UDS datagram socket。


我们可以使用 stat 命令来查看 socket 文件的具体信息:


stat /tmp/stream.sock /tmp/datagram.sock  File: ‘/tmp/stream.sock’  Size: 0               Blocks: 0          IO Block: 4096   socketDevice: fd02h/64770d    Inode: 134386049   Links: 1Access: (0775/srwxrwxr-x)  Uid: ( 1002/    flydean)   Gid: ( 1002/    flydean)Access: 2022-03-01 22:33:21.533000000 +0800Modify: 2022-03-01 22:33:21.533000000 +0800Change: 2022-03-01 22:33:21.533000000 +0800 Birth: -  File: ‘/tmp/datagram.sock’  Size: 0               Blocks: 0          IO Block: 4096   socketDevice: fd02h/64770d    Inode: 134386050   Links: 1Access: (0775/srwxrwxr-x)  Uid: ( 1002/    flydean)   Gid: ( 1002/    flydean)Access: 2022-03-01 22:33:22.306000000 +0800Modify: 2022-03-01 22:33:22.306000000 +0800Change: 2022-03-01 22:33:22.306000000 +0800 Birth: -
复制代码

使用 nc 连接到 Unix domain Socket 服务

nc 是一个非常强大的工具,除了可以进行 TCP,UDP 连接之外,还可以进行 UDS 的连接,我们需要使用到下面的参数:


  -U, --unixsock             Use Unix domain sockets only  -u, --udp                  Use UDP instead of default TCP  -z                         Zero-I/O mode, report connection status only
复制代码


-U 表示连接的是一个 unixsocket。-u 表示是一个 UDP 连接。


默认情况下 nc 使用的是 TCP 连接,所以不需要额外的参数。


另外我们直接建立连接,并不发送任何数据,所以这里使用-z 参数。


先连接 Stream UDS 看看:


nc -U -z /tmp/stream.sock
复制代码


如果没有输出任何异常数据,说明连接成功了。


然后再连接 Datagram UDS 看看:


nc -uU -z /tmp/datagram.sock
复制代码


同样的,如果没有任何异常数据,说明 Socket 连接成功了。

总结

在本章我们详细介绍了 Unix Domain Socket 的含义,并且使用了 unix 中的一些工具实现了 UDS 的建立,检测和连接。基本上描述了 UDS 的使用情况。


本文已收录于 http://www.flydean.com/17-unix-domain-socket/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 刚刚阅读数: 2
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
网络协议之:socket协议详解之Unix domain Socket_socket_程序那些事_InfoQ写作平台