rsh Usage Tips

风行水上 @ 2014-07-31 14:58:32
标签:

rsh有两种使用模式:

  • rsh $host : 远程登录,启动交互式进程。
  • rsh $host $command :远程执行命令,并显示输出。

rsh $host $command

rsh $host $command的作用是:

  • 在远程机器上执行命令$command
  • 通过网络连接(socket)重定向当前进程和远端进程的标准输入和标准输出
  • 远端rsh进程在远端进程结束后结束
  • 本地rsh进程读取远端进程的标准输出直到结束(EOF)

深刻理解这个执行过程有助于理解各种“奇怪”的现象和用法。

+ Suspended (tty input)

$ rsh localhost infinite-loop &
[1]  + Suspended (tty input)         rsh pv007 infinite-loop

$ rsh -n localhost infinite-loop &
# 执行正常

后台执行rsh命令时,提示了和标准输入相关的错误信息。这是因为rsh默认会把当前窗口的标准输入重定向到远端进程。
而本地rsh进程作为后台程序运行的话,标准输入被“阻塞”了。

通过-n选项制定不需要重定向标准输入(stdin)。

远端进程的执行

执行命令rsh somehost infinite-loop

在远端机器上查看相关进程:

$ pstree -a -p 3353
in.rshd,3353
  └─csh,3363 -c infinite-loop
      └─infinite-loop,3632 /u/szhang/bin/infinite-loop

可以看出,远端机器上的rshd进程负责启动远端进程。而且可以看出是通过csh -c的方式启动的(这里用户的默认Shell是C Shell)。

远端进程的标准IO

检查远端进程的文件描述符:

$ ls -l /proc/3363/fd /proc/3632/fd
/proc/3363/fd:
total 0
lrwx------. 1 Jul 30 23:47 16 -> socket:[1184748899]
lrwx------. 1 Jul 30 23:47 17 -> socket:[1184748899]
l-wx------. 1 Jul 30 23:47 18 -> pipe:[1184749092]
lrwx------. 1 Jul 30 23:47 19 -> socket:[1184748899]

/proc/3632/fd:
total 0
lrwx------. 1 Jul 30 23:47 0 -> socket:[1184748899]
lrwx------. 1 Jul 30 23:47 1 -> socket:[1184748899]
l-wx------. 1 Jul 30 23:47 2 -> pipe:[1184749092]

可以看出远端里程的标准输入输出是被重定向到socket上的:

  • stdin 和 stdout 共享一个socket连接
  • stderr 则通过一个pipe重定向(重定向到stdout ???)

rsh 的返回值

rsh程序自身的返回值表明的是rsh自身的运行状况,而不是远端进程的返回值。

获得远端进程的返回值

# 远端是C Shell
$ rsh $host "$command ; echo $status"

# 远端是Bash Shell
$ rsh $host "$command ; echo $?"

# 远端Shell类型不确定
$ rsh $host "sh -c '$command ; echo $?'"

启动远端进程所用的Shell

由于用于启动远端进程的Shell类型是未知的,而有些操作的语法在不同Shell里是不同的。

比如输入输出重定向、命令返回值等。

解决该问题的方法之一是通过明确指定的Shell来启动真正需要的里程。比如:

# 不确定远端Shell的类型,显式通过Bash Shell来启动需要的进程
$ rsh -n $host "sh -c '$command > /dev/null 2>&1'"

另一种思路,则是通过一个wrapper程序来启动真正的命令。

通过rsh在远端执行后台进程

想在远端机器上执行后台进程。命令rsh $host "$command &"是不起作用的,会导致本地的rsh进程不能结束。

背后的原因应该是,$command的标准输入输出通常仍然绑定在rsh连接的socket上,从而导致本地的rsh进程无法读取到文件结束符EOF。

知道了原因就知道该怎么办了,关键是关闭后台进程续定在rsh连接上的标准输入输出。

# 如果远端Shell是C Shell
$ rsh -n $host "$command >& /dev/null &"

# 如果远端Shell是Bash Shell
$ rsh -n $host "$command > /dev/null 2>&1 &"

# 不确定远端Shell的类型
$ rsh -n $host "sh -c '$command > /dev/null 2>&1 &'"

但上面这样重定向的办法有个缺点是不能得到任何远端进程的输出,而有时我们希望获得一些输出信息。
这时就需要远端进程能够以守护进程(daemon)的方式运行。

这种情况下,rsh命令可以简单地写作:$ rsh -n $host "$command &"

远端后台进程的内容用Tcl表示,大意如下:

#/bin/env tclsh

puts "I am a background job"
puts "This Can Be Seen by Remote rsh Process"

close stdout
close stderr

# rsh连接到此应该结束。

puts "This Can NOT Be Seen by Remote rsh Process"

更进就步,我们可以甚至忽略rsh命令中的后台运行符:$ rsh -n $host "$command"

这时远端进程需要通过fork的方式结束自己,并启动真正的后台进程(守护进程)。

rsh: Connection refused

根据 http://blog.sina.com.cn/s/blog_644c3be70100gfm5.html 的描述:

$ rsh $remote_host
connect to address 192.168.1.15: Connection refused
Trying krb4 rlogin…
connect to address 192.168.1.15: Connection refused
trying normal rlogin (/usr/bin/rlogin)
Last login: Fri Jul 28 10:33:29 from ...

# 检查rlogin程序的来源
$ rpm -qf `which rlogin` 
krb5-workstation-1.3.4-27

# 删除 krb5-workstation
$ rpm -e krb5-workstation

# 检查rlogin程序的来源
$ rpm -qf `which rlogin`
rsh-0.17-25.3

# rsh 测试
$ rsh $remote_host

poll: protocol failure in circuit setup

参见:TCP Connection连接数过多引起的rsh失败

rsh进程的阻塞和超时处理

在程序中调用rsh $host $command时可能由于各种奇怪的原因发生rsh进程的阻塞,这不是我们希望看到的。

我们希望设置一个超时(timeout)机制来解决这个问题。

在Tcl程序中的一种实现可以这样: TODO

标签:

分享到:
comments powered by Disqus

32/36ms