就像我之前提到的,zsh 脚本是可以直接使用 socket 文件(UNIX domain socket 所使用)或者 TCP 和其他进程通信的。如果进程都在本地,用 socket 文件效率更高些,并且不要占用端口,权限也更好控制。如果是在不同机器,可以使用 TCP。
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 连接的方式和使用 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 来实现两个脚本之间通信的方法。