網路協議之: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.sock
srwxrwxr-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 tmp
u_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 socket
Device: fd02h/64770d Inode: 134386049 Links: 1
Access: (0775/srwxrwxr-x) Uid: ( 1002/ flydean) Gid: ( 1002/ flydean)
Access: 2022-03-01 22:33:21.533000000 +0800
Modify: 2022-03-01 22:33:21.533000000 +0800
Change: 2022-03-01 22:33:21.533000000 +0800
Birth: -
File: 『/tmp/datagram.sock』
Size: 0 Blocks: 0 IO Block: 4096 socket
Device: fd02h/64770d Inode: 134386050 Links: 1
Access: (0775/srwxrwxr-x) Uid: ( 1002/ flydean) Gid: ( 1002/ flydean)
Access: 2022-03-01 22:33:22.306000000 +0800
Modify: 2022-03-01 22:33:22.306000000 +0800
Change: 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的使用情況。
本文已收錄於 //www.flydean.com/17-unix-domain-socket/
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!