導讀
就像我之前提到的,zsh 指令碼是可以直接使用 socket 檔案(UNIX domain socket 所使用)或者 TCP 和其他程式通訊的。如果程式都在本地,用 socket 檔案效率更高些,並且不要佔用埠,許可權也更好控制。如果是在不同機器,可以使用 TCP。
Socket 檔案
UNIX domain socket 是比管道更先進的程式通訊方法,是全雙工的方式,並且穩定性更好。但效能比管道差一些,不過一般效能瓶頸都不會出現在這裡,不用考慮效能問題。而且在一個 socket 檔案上可以建立多個連線,更容易管理。另外如果通訊方式從 socket 檔案改成 TCP,只需要修改很少的程式碼(建立和關閉連線的程式碼稍微改一下),而從管道改成 TCP 則要麻煩很多。
所以建議用 zsh 寫程式互動指令碼的話,直接使用 socket 檔案,而不是命名管道(匿名管道就能滿足需求的簡單場景忽略不計)。
Socket 檔案的用法:
# 監聽連線端
# 首先要載入 socket 模組
% zmodload zsh/net/socket
% zsocket -l test.sock
% listenfd=$REPLY
# 此處阻塞等待連線
% zsocket -a $listenfd
# 連線建立完成
% fd=$REPLY
% echo $fd
5
# 然後 $fd 就可讀可寫
% cat <&$fd
good複製程式碼
# 發起連線端
# 首先要載入 socket 模組
% zmodload zsh/net/socket
% zsocket test.sock
# 連線建立完成
% fd=$REPLY
% echo $fd
4
# 然後 $fd 就可讀可寫
% echo good >&$fd複製程式碼
連線建立後,怎麼用就隨意了。實際使用時,要判斷 fd 看連線是否正常建立了。通常使用 socket 檔案要比在網路環境使用 TCP 穩定性高很多,一般不會連線中斷或者出其他異常。另外可以在 zsocket 後加 -v 引數,檢視詳細的資訊(比如使用的 fd 號)。
關閉連線:
# 發起連線端
# fd 是之前存放 fd 號的變數,不需要加 $
% exec {fd}>&-
# 監聽連線端
% exec {listenfd}>&-
% exec {fd}>&-
# 刪除 socket 檔案即可,如果下次再使用會重新建立,該檔案不能重複使用
% rm test.sock複製程式碼
TCP
使用 TCP 連線的方式和使用 socket 檔案基本一樣。
# 監聽連線端
# 首先要載入 tcp 模組
% zmodload zsh/net/tcp
% ztcp -l 1234
% listenfd=$REPLY
# 此處阻塞等待連線
% ztcp -a $listenfd
# 連線建立完成
% fd=$REPLY
% echo $fd
3
# 然後 $fd 就可讀可寫
% cat <&$fd
good複製程式碼
# 發起連線端
# 首先要載入 tcp 模組
% zmodload zsh/net/tcp
% ztcp 127.0.0.1 1234
# 連線建立完成
% fd=$REPLY
% echo $fd
3
# 然後 $fd 就可讀可寫
% echo good >&$fd複製程式碼
關閉連線:
# 發起連線端
# fd 是之前存放 fd 號的變數
% ztcp -c $fd
# 監聽連線端
% ztcp -c $listenfd
% ztcp -c $fd複製程式碼
程式樣例
recv_tcp,監聽指定埠,並輸出傳送過來的訊息。使用方法:recv_tcp 埠
#!/bin/zsh
zmodload zsh/net/tcp
(($+1)) || {
echo "Usage: ${0:t} port"
exit 1
}
ztcp -l $1
listenfd=$REPLY
[[ $listenfd == <-> ]] || exit 1
while ((1)) {
ztcp -a $listenfd
fd=$REPLY
[[ $fd == <-> ]] || continue
cat <&$fd
ztcp -c $fd
}複製程式碼
send_tcp,用來向指定機器的指定埠發一條訊息。使用方法:send_tcp 機器名 埠 訊息 (機器名可選,如果沒有則發到本機,訊息可以包含空格)
#!/bin/zsh
zmodload zsh/net/tcp
(($# >= 2)) || {
echo "Usage: ${0:t} [hostname] port message"
exit 1
}
if [[ $1 == <0-65535> ]] {
ztcp 127.0.0.1 $1
} else {
ztcp $1 $2
shift
}
fd=$REPLY
[[ "$fd" == <-> ]] || exit 1
echo ${*[2,-1]} >&$fd
ztcp -c $fd複製程式碼
總結
本文介紹了使用 socket 檔案或者 TCP 來實現兩個指令碼之間通訊的方法。
全系列文章地址:github.com/goreliu/zsh…
付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活定價,歡迎諮詢,微信 ly50247。