Socket协议简介详解上一篇我们讲了Socket中的StreamSocket和DatagramSocket。这两个Socket通常是基于tcp和udp协议进行数据传输的。这两个Sockets有一个共同的特点,就是都需要一个IP地址和端口来建立客户端和服务器端的连接。那么今天我们就来讲解一个特殊的socket。这种套接字不需要使用传统的IP地址和端口,而是利用文件系统在程序之间交换数据,而且这种套接字只能在Unix系统上使用。这样的套接字就是我们今天要讲解的Unix域套接字。什么是Unix域Socket什么是Unix域Socket?从名字我们可以看出这个Socket是和unix域相关的,也就是说这个socket在unix下需要使用一些特殊的功能。我们先考虑常用的windows系统和unix系统。它们之间最大的区别是什么?其实最大的区别就是Unix操作系统中的一切都可以看作是一个文件,包括程序运行的一些信息。那么我们是否可以直接利用这些程序运行时产生的文件来实现不同程序之间的数据交互呢?答案是肯定的。这就是我们今天要讨论的Unix域Socket。Unixdomainsocket可以简称为UDS,不同程序之间的数据可以通过文件系统在操作系统层进行交换。对于程序本身来说,只需要读写共享的socket文件即可,也就是说不同的程序通过socket文件进行数据交换。与基于IP和端口的Socket一样,Unix域Socket也可以分为StreamSocket和DatagramSocket。我们看到最多Unixdomainsocket的地方可能就是docker了。docker作为一种容器技术,需要与物理机进行快速的数据传输和信息交换。通常,UDS文件以.socket结尾。我们可以在/var/run目录下使用如下命令查找:find。-name"*.sock"如果你有docker运行,你可以得到如下结果:./docker.sock./docker/libnetwork/6d66a24bfbbfa231a668da4f1ed543844a0514e4db3a1f7d8001a04a817b91fb.sock./docker/libcontainerd/docker-containerd.sock可以看到docker通过以上三个sock文件进行通信。使用socat创建UnixDomainSockets前面提到socat是一个万能工具,不仅可以创建tcp监听服务器,还可以创建udp监听服务器,当然对于UDS来说不是问题。下面看一下使用socat创建UDS服务器需要的参数:unix-listen:groups=FD,SOCKET,NAMED,LISTEN,CHILD,RETRY,UNIXunix-recvfrom:groups=FD,SOCKET,NAMED,CHILD,RETRY,UNIX这里需要用到unix-listen和unix-recvfrom这两个参数,unix-listen表示创建一个基于流的UDS服务,unix-recvfrom表示创建一个基于数据报的UDS.可以看到这两个参数后面还需要传入一个文件名,表示UDSsocket的地址。我们可以这样使用:socatunix-listen:/tmp/stream.sock,fork/dev/null&socatunix-recvfrom:/tmp/datagram.sock,fork/dev/null&这里我们使用/tmp/datagram。sock来表示这个套接字信息。fork参数表示程序收到包后继续运行。如果不使用fork,程序会自动退出。socat之后本来连接了一个双向地址,这里我们使用/dev/null,意思是丢弃所有的收入信息。运行后,我们可能会得到如下结果:[1]27442[2]27450表示程序执行成功,返回程序的pid。使用ss命令查看Unix域Socket在使用ss命令之前,先看一下使用socat生成的两个文件:srwxrwxr-x1flydeanflydean0Mar221:58stream.socksrwxrwxr-x1flydeanflydean0Mar221:59datagram.sock可以看到这两个文件的权限。rwx大家都知道,就是读、写、执行权限。那么第一个s是什么?第一位表示文件类型,s表示socket文件。扩展一下,这个位置还可以有其他几个选项:p、d、l、s、c、b、-:其中p代表命名管道文件,d代表目录文件,l代表符号链接文件,-代表普通文件,s代表socket文件,c代表字符设备文件,b代表块设备文件。接下来我们使用ss命令查看之前建立的UDS服务。这里需要用到以下参数:-n,--numeric不解析服务名-l,--listening显示监听套接字-x,--unix只显示Unix域套接字这里我们需要用到上面3个选项,x表示显示UDS,因为是监听,所以使用-l参数,最后我们希望看到具体数字而不是被解析成服务名,所以这里使用-n参数。我们可以尝试执行如下命令:ss-xln会输出很多,我们可以这样grep我们需要的socket:ss-xln|greptmpu_strLISTEN05/tmp/stream.sock11881005*0u_dgrUNCONN00/tmp/datagram.sock11882190*0u_str表示UDS流套接字,u_dg表示UDS数据报套接字。我们可以使用stat命令查看socket文件的具体信息:stat/tmp/stream.sock/tmp/datagram.sockFile:'/tmp/stream.sock'Size:0Blocks:0IOBlock:4096socketDevice:fd02h/64770dInode:134386049链接:1访问:(0775/srwxrwxr-x)Uid:(1002/flydean)Gid:(1002/flydean)访问:2022-03-0122:33:21.533000000+0800222-02-01:33:21.533000000+0800Change:2022-03-0122:33:21.533000000+0800Birth:-File:'/tmp/datagram.sock'Size:0Blocks:0IOBlock:4096socketDevice:fd02h/64770dInode38:6链接:1访问:(0775/srwxrwxr-x)Uid:(1002/flydean)Gid:(1002/flydean)访问:2022-03-0122:33:22.306000000+0800修改:2022-03-0122:33:22.306000000+0800Change:2022-03-0122:33:22.306000000+0800诞生:-使用nc连接Unix域Socket服务nc是一个非常强大的工具,除了TCP和UDP连接,它还可以制作UDSconnections,我们需要使用以下参数:-U,--unixsock仅使用Unix域套接字-u,--udpUseUDP代替默认的TCP-z零I/O模式,仅报告连接状态-U表示连接是unixsocket-u表示是UDP连接。默认情况下nc使用TCP连接,因此不需要额外的参数。另外,我们直接建立连接,不发送任何数据,所以这里使用了-z参数。先连接StreamUDS,看:nc-U-z/tmp/stream.sock如果没有异常数据输出,则连接成功。然后连接DatagramUDS看:nc-uU-z/tmp/datagram.sock同理,如果没有异常数据,说明Socket连接成功。小结本章详细介绍了UnixDomainSocket的含义,并使用了Unix中的一些工具来实现UDS的建立、检测和连接。基本上介绍了UDS的用法。本文已收录于http://www.flydean.com/17-unix-domain-socket/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等着你等你发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!