Zsh 開發指南(第十七篇 使用 socket 檔案和 TCP 實現程式間通訊)

陌辭寒發表於2019-01-16

導讀

就像我之前提到的,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。

相關文章