在macOS上用supervisor构建稳定的SSH转发

2 篇文章 0 订阅

之前一直使用SSH指定端口转发请求,一直能用,但是很烦。因为每次都要输入密码之类的,而且经常会断开,断开后又输密码,神烦。前几日决心解决这个问题,作为一名Python开发者,首先想到的就是supervisor,最后也证明这个想法行得通。

brew install supervisor把它安装上,然后运行brew service start supervisor运行起来。打开/usr/local/etc/supervisor.d,然后在下面建立一个ssh_d.ini文件,内容如下:

[program:ssh_d]
command=你的SSH命令
autostart=true
autorestart=true
numprocs=1
killasgroup=true
stopasgroup=true

其中autostartautorestart参数能够确保你的SSH进程始终在。然后运行supervisorctl start ssh_d把它运行起来。但这一步不一定能够成功,因为你可能没有配置免密码登陆服务器。


ssh-keygen -t rsa可以为自己生成配对的公钥和密钥,注意保存的文件名,以免和其它服务器的混了,比如我自已输入的是ssh_d_id_rsa

生成后,把ssh_d_id_rsa文件放到~/.ssh/目录下。用scpssh_d_id_rsa.pub上传到你的服务器,并把它加到服务器的 ~/.ssh/authorized_keys文件中。然后配置本机的/etc/ssh/ssh_config文件,加上这么一节:

Host 你的主机IP
    SendEnv LANG LC_*
    IdentityFile ~/.ssh/ssh_d_id_rsa

这时候你再试试supervisorctl restart ssh_d,估计就能运行成功了。可以在浏览器里试一下代理,有没有转发请求出去。


以上,基本上使用起来就没有问题了。不过好像时间久了SSH进程会有点不靠谱,具体啥原因也不好深究,我的方案是定时,15分钟,让supervisor重启一次SSH进程。

在macOS上做定时任务,一开始我是延用了crontab,发现各种折腾,都没有效果。最后靠谱的是launchd。具体的操作是先把supervisor重启进程的命令写成脚本,比如 ~/supervisorctl_restart_ssh_d.sh,内容如下:

#!/bin/sh
/usr/local/bin/supervisorctl restart ssh_d

保存后,注意用chmod +x给这个脚本文件加上可执行权限,不然就会失败。

下一步是进入~/Library/LaunchAgents目录,然后写一个ssh_d.crontab.plist的文件,里面的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>ssh_d.crontab</string>

  <key>ProgramArguments</key>
  <array>
    <string>改成你的supervisorctl_restart_ssh_d.sh文件的绝对路径</string>
  </array>

  <key>StartInterval</key>
  <integer>900</integer>

  <key>RunAtLoad</key>
  <true/>
    <key>StartInterval</key>
  <integer>900</integer>

  <key>RunAtLoad</key>
  <true/>

  <key>Debug</key>
  <true/>

  <key>StandardErrorPath</key>
  <string>/tmp/AlTest1.err</string>

  <key>StandardOutPath</key>
  <string>/tmp/AlTest1.out</string>
</dict>
</plist>

然后运行launchctl load ssh_d.crontab.plist装裁这个命令,成功的话,你可以看到你的SSH的进程ID变化了,这就表示它成功重启了SSH进程。

另外也可以用命令来查看任务运行的结果:

 launchctl list | grep ssh_d
-	0	ssh_d.crontab

中间的 0 表示运行成功,如果是非 0 值,比如 78,可以使用另一个命令来看看是表示什么意思:

 launchctl error 78
78: Function not implemented

至此,SSH进程常用常新,可用性增强了不少。


不过如果合上mac的屏幕,较长时间之后再打开,你会发现SSH连接已经断开,但并不会自动重连。

目前这个痛点还没有好的解决方案。我暂时是用浏览器打开http://127.0.0.1:9001页面,这是supervisor的Web控制台。然后手动启一下ssh_d,因为不需要输入密码,而且这种情况一天也没有几次,尚可接受。

如果你打不开 http://127.0.0.1:9001,可以编辑/usr/local/etc/supervisord.ini文件,把下面两行前面的注释去除,

[inet_http_server]         ; inet (TCP) server disabled by default
port=127.0.0.1:9001        ; ip_address:port specifier, *:port for all iface

然后再运行brew service restart supervisor就可以了。


更新:

一觉醒来,有了灵感:屏幕亮起,也就是由睡眠到唤醒,是一种事件啊。launchd应该有机制可以获取这个事件,然后做一些事情的。一搜索,果然有方法。具体就是在 ssh_d.crontab.plist文件中加入下面这几行:

  <key>WatchPaths</key>
  <array>
    <string>/Library/Preferences/SystemConfiguration</string>
  </array>

原理是当唤醒macOS时,这个文件夹(也就是系统配置)会有一些变化,比如WIFI之类的,所以当这个文件夹变化时,就重启一下我们的SSH进程,就不需要再手动去重启了。

真香。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在MacOS上使用Java8做本地通知需要使用JavaFX。 首先,确保你已经安装了Java8。然后,使用以下步骤进行操作: 1. 在Eclipse中新建一个JavaFX项目。 2. 在`Main`类中加入以下代码: ``` import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.GridPane; import javafx.scene.text.Text; import javafx.stage.Stage; import javafx.stage.StageStyle; public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("JavaFX Local Notification Example"); primaryStage.initStyle(StageStyle.UNDECORATED); GridPane grid = new GridPane(); grid.setAlignment(Pos.CENTER); grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(25, 25, 25, 25)); Button btn = new Button(); btn.setText("Show Notification"); btn.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { showNotification(); } }); grid.add(btn, 0, 1); Scene scene = new Scene(grid, 300, 275); primaryStage.setScene(scene); primaryStage.show(); } private void showNotification() { TrayNotification tray = new TrayNotification(); tray.setTitle("Notification"); tray.setMessage("This is a local notification."); tray.setNotificationType(NotificationType.SUCCESS); tray.showAndWait(); } } ``` 3. 运行项目,点击“Show Notification”按钮,即可看到本地通知。 注意:你可能需要导入TrayNotification类,它可以在这里获取:https://github.com/PureElegance/TrayNotification 希望这对你有帮助! ### 回答2: 要在MacOS上使用Java 8做本地通知,你可以使用Java的桌面通知功能和MacOS的通知中心。 首先,你需要确保你的MacOS版本支持桌面通知。从MacOS 10.8开始,Apple引入了桌面通知功能,并在通知中心中进行管理。 然后,你需要创建一个Java应用程序,并添加依赖项以使用Java的桌面通知功能。你可以在你的项目中添加javax.swing和java.awt包,它们提供了创建用户界面所需的类和方法。 接下来,你需要编写代码以创建和发送通知。你可以使用Java的javax.swing.JOptionPane类来创建一个简单的弹窗,然后使用java.awt包中的Toolkit类将其转换为通知。 下面是一个简单示例代码: ```java import javax.swing.JOptionPane; import java.awt.Toolkit; public class NotificationExample { public static void main(String[] args) { // 创建一个弹窗 JOptionPane.showMessageDialog(null, "这是一个通知"); // 将弹窗转换为通知 Toolkit.getDefaultToolkit().beep(); } } ``` 编译和运行这个代码后,你会在你的MacOS上收到一个简单的通知。你也可以根据你的需要添加更多的功能,比如自定义通知标题、内容和图标等。 总结来说,要在MacOS上使用Java 8做本地通知,你需要确保你的MacOS版本支持桌面通知,并在你的Java应用程序中添加依赖项以使用Java的桌面通知功能。然后,你可以使用Java的弹窗功能和MacOS的通知中心来创建和发送通知。 ### 回答3: 在MacOS上使用Java8进行本地通知有以下几个步骤: 1. 确保已经安装了Java开发工具,可以在终端中运行`java -version`命令来验证是否安装。如果没有安装,你可以去Oracle官网下载并安装最新的Java8版本。 2. 创建一个Java项目,可以使用任何喜欢的IDE(比如IntelliJ IDEA)或者纯文本编辑器。在项目中创建一个Java类作为入口点。 3. 导入所需的Java库以进行本地通知。Java提供了`java.awt`和`javax.swing`库来处理图形界面,可以使用这些库来创建通知窗口。 4. 在Java类中,创建一个通知窗口的方法。可以使用`JFrame`类来创建一个可自定义的窗口,其中包括通知的标题、内容和图标。样例代码如下: ```java import java.awt.Dimension; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.JLabel; public class Notification { public static void showNotification(String title, String message) { JFrame frame = new JFrame(); frame.setSize(400, 200); // 设置通知窗口的大小 frame.setTitle(title); // 设置通知的标题 // 获取屏幕尺寸 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int screenWidth = (int) screenSize.getWidth(); int screenHeight = (int) screenSize.getHeight(); // 设置窗口的位置居中显示在屏幕上 frame.setLocation((screenWidth - frame.getWidth()) / 2, (screenHeight - frame.getHeight()) / 2); // 设置窗口不可调整大小 frame.setResizable(false); // 在窗口中添加通知内容 JLabel label = new JLabel(message); frame.add(label); frame.setVisible(true); } } ``` 5. 在项目的其他部分调用`showNotification()`方法来显示通知窗口。在调用时,传入通知窗口的标题和内容。例如: ```java public class Main { public static void main(String[] args) { Notification.showNotification("通知标题", "这是一条通知消息!"); } } ``` 这样,当你运行该Java程序时,就会在屏幕中央显示一个具有指定标题和内容的通知窗口。你可以根据需要对窗口进行自定义,比如添加更多的组件或者调整窗口的样式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值