我希望通过 SSH 从远程主机建立一个端口。我希望将其实现为 oclif
插件;我希望用户体验如下所示:
laptop$ give-jupyter
http://localhost:4040/
laptop$ kill-jupyter
laptop$
...这应该相对简单;我只是*需要维护一个pidfile,对吗?类似的东西:
import child_process from 'child_process';
const childProcess = child_process.spawn('ssh', [/* flags */], {detached: true, stdio: 'ignore'});
childProcess.unref();
writeToSomePidfile({childProcess.pid);
然而,所有这些基本上都是无关紧要的。问题是我必须弄清楚这些标志!哦,那好吧;这有效:
laptop$ ssh machine -L 4040:localhost:4040
machine$
...但是,它也会在远程端打开一个shell。没问题,man ssh
说这就是 -L
的用途:
laptop$ ssh machine -LN 4040:localhost:4040
这很好,但它现在劫持了我用户的 shell。好吧,让我们将进程发送到后台:
laptop$ ssh machine -LN 4040:localhost:4040 &
laptop$ f
f: file not found
laptop$ fg
^C
ssh
的后台版本与 STDIN
上的 shell 进入竞争条件,一切都非常糟糕。好吧,man ssh
说这就是 -n
的用途:
laptop$ ssh machine -nLN 4040:localhost:4040 &
laptop$Job 1, 'ssh machine -nNL 40…' has ended
...好吧,那太好了:ssh
现在立即退出,隧道也是如此。
SSH 提到 -f
应该启用某种后台模式,但 ssh -fnN
也没有这样做; ssh
立即退出。
如果我不能拥有好东西,也许我可以用一个即使没有标准输入也能永远运行的命令来近似它们。服务器故障suggests:
laptop$ ssh machine -nL 4040:localhost:4040 tail -f /dev/null &
laptop$
还是不行?!很好:
laptop$ ssh machine -nL 4040:localhost:4040 sleep infinity &
laptop$
这似乎在一个微小过程的低成本下起作用,远比我在编写此问题时尝试过的其他迭代要好得多,主要涉及 yes
...
然而,是否有一种...在后台运行 SSH 隧道的不那么笨拙的方法?加分项:我也需要它在 OSX 笔记本电脑上工作...
答案 0 :(得分:2)
我会亲自在系统上创建一个文件,该文件使用 ssh -M -S ~/jupyter-tunnel -o "ExitOnForwardFailure yes" -fN machine -L 4040:localhost:4040
控制套接字绑定到隧道。肯定比处理 PID 更容易。
ssh -S ~/jupyter-tunnel -O exit machine
PImage stage;
PImage model;
PImage [] hat = new PImage [5];
PImage [] pants = new PImage [4];
PImage [] shirt = new PImage [5];
int selectedHat = -1;
int selectedPants = -1;
int selectedShirt = -1;
int choice = 0;
int page = 0;
void setup(){
size (800,800);
stage = loadImage("background.png");
background(255);
image(stage,0,0);
initializeImages()
}
void draw(){
println(mouseX, mouseY); //398, 237 for hats.
image(stage,0,0);
if (selectedHat > 0) {
image(hat[selectedHat], 349,98);
}
if (selectedPants > 0) {
image(pants[choice], 228,263);
}
}
void mouseClicked() {
if(dist(404,363, mouseX, mouseY) <90 && mousePressed) {
selectedPants = floor(random(4));
}
if(dist(398,237, mouseX, mouseY) <90 && mousePressed) {
selectedHat = floor(random(4));
}
}
void initializeImages() {
hat[0] = loadImage ("hat1.png");
hat[1] = loadImage ("hat2.png");
hat[2] = loadImage ("hat3.png");
hat[3] = loadImage ("hat4.png");
pants[0] = loadImage ("pant1.png");
pants[1] = loadImage ("pant2.png");
pants[2] = loadImage ("pant3.png");
pants[3] = loadImage ("pant4.png");
}