![如何在不使用 SSH 的情况下远程告诉 Mac 进入睡眠状态?](https://linux22.com/image/1614858/%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8D%E4%BD%BF%E7%94%A8%20SSH%20%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E8%BF%9C%E7%A8%8B%E5%91%8A%E8%AF%89%20Mac%20%E8%BF%9B%E5%85%A5%E7%9D%A1%E7%9C%A0%E7%8A%B6%E6%80%81%EF%BC%9F.png)
我需要帮助让 Mac 不使用 SSH 进入睡眠状态。几乎任何其他方法都可以接受。
背景故事:产品销售员和项目经理无需询问程序员即可销售产品。程序员现在必须使用只能发送 UDP 和 TCP 字符串/十六进制的产品来打开和关闭 Mac。它确实允许进行痛苦的手动 Telnet 过程,而 SSH 完全不在考虑范围内。我们 100% 不是 MAC 用户。
我们尝试过的事情:
- homebrew 的 telnetd - 拒绝打开,控制台状态运行 0 秒,10 秒后重新生成。搜索如何调试这个问题已经导致上百个死胡同“它应该可以正常工作!”当它不能正常工作时,这是没用的。
- Mac 的 NC 命令。虽然我们能够在端口 3000 和 3001 上在我们的控制服务器和 Mac 之间来回打开 udp 会话,但在谷歌搜索并找到解决方案后,发现除了启动命令之外,它几乎无能为力。
我们尝试将 NC 命令放入 bash 脚本中。这很糟糕,似乎在尝试捕获 NC 的实时输出时,它会锁定该行上的脚本,因此永远不会进行解析。我们做了一个非常简单的测试脚本,如下所示。
output=$(nc -u -l -k 3000; kill$!) echo "$output"
再次,Mac 新手,Bash 新手。Google 和 Stack Searchboxes 都让我们失望了!我们确实找到了“pmset sleepnow”命令,它可以完成我们想要的功能,所以就是这样。
只是寻找一种简单的方法来接收“睡眠”的 UDP 消息并让 Mac 进入睡眠状态。
答案1
关于nc
和脚本。
如果nc
你使用类似于我的 Kubuntu 中的那个(它似乎是 OpenBSD 实现),那么-k
意味着“保持倾听”,它将使该工具绝不会自动退出。但即使没有-k
,nc
使用 UDP 也无法判断通信是否结束,因为 UDP 是无连接的。当收到第一条消息时,nc
将固定在远程端的地址和端口上;除非您使用 ,否则它将保持此状态-w
。
如果你允许nc
退出,然后才解析收到的内容,那么就没有监听进程来处理可能的第二次连接尝试。如果任何给定端口上的通信应该使计算机进入睡眠状态:
nc -w 0 -u -l 3000 >/dev/null && echo "Sleep now!"
# replace echo with pmset or whatever
使用-w 0
和-k
允许我接收从不同地址/端口发送的短消息。该工具不会退出,但可以通过管道传输接收到的数据进行分析:
nc -w 0 -k -u -l 3000 | while IFS= read -r line; do
[ "$line" = sleep ] && echo "Sleep now!"
done
# replace echo with pmset or whatever
对于短 UDP 消息来说可能没问题。一般来说,存在以下几个问题:
我猜测以两个或多个数据包的形式传入的消息可能会
-w 0
过早触发。来自两个源的较长传输可能会交错。为了防止这种情况,您可以:- 使用更长的超时时间(例如
-w 1
)并希望它足够; - 使用 TCP,因此
nc
知道当前连接何时结束(但请注意,如果另一台设备在没有正式终止连接的情况下消失,nc
则会等待;因此-w
仍然有用;没有-w
TCP keepalive 机制最终会终止连接并解除阻塞nc
,这可能在大约两个小时后发生);
- 使用更长的超时时间(例如
至少在我的 Kubuntu 中,
nc -k
它可以同时处理多个连接,也就是说,当它处理第一个连接时,监听似乎没有间隙。来自不同连接的数据仍然按顺序出现在 stdout 中nc
,因此只要第一个连接处于活动状态,循环while read …
就不会看到来自其他连接的任何内容。单个(恶意?)连接可能会阻止其他(合法?)连接触发所需的操作。
出于这些原因,建议采用分别分析每个连接数据的方法。您可以使用 来执行此操作socat
。比较这是我的另一个答案。对于你来说,一个基本的存根可能是:
socat -T 1 UDP-LISTEN:3000,fork SYSTEM:'
IFS= read -r line && [ "$line" = sleep ] && echo "Sleep now!" >/dev/tty
'
# again, replace echo with pmset or whatever
shell 代码中没有循环。我们从每个传入连接中读取并测试一行。
笔记:
- 我
socat
在我的 Kubuntu 上使用了它。我不太了解 Mac,但是看到这个。 - 根本就没有任何身份验证。
IFS= read -r line
期望行正确终止,因此连接设备应发送类似sleep\n
表示\n
换行符 (LF
,0x0A
) 的内容。
答案2
长nc
答案可能是最好的答案,特别是如果你不熟悉 Mac(但熟悉 Linux)。另一个选择,我过去曾使用过,是编写一个简单的 CGI 脚本(如果你同意在 Mac 上运行 Apache)。每当运行 CGI 时,它都可以在某个目录中创建一个文件(任何地方,这并不重要,只要 Apache/CGI 可以在那里写入)。
然后,单独编写一个launchd
代理(类似于其他 Linux 中的服务/守护程序),用于“监听”此目录中的文件。当代理(实际上是代理背后的脚本)检测到文件时,让 Mac 进入睡眠状态!
它更复杂,但我以前用过!出于某种原因(我猜是出于安全原因),您可以直接从 CGI 调用睡眠诱导可执行文件或 AppleScript,因此使用此文件作为信号量是一种不错的解决方法。