Process dies, if it is run via paramiko ssh sessio

2019-04-17 10:03发布

问题:

I just want to run tcpdump in background using paramiko.

Here is the part of the code:

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=login, password=password)
transport = ssh.get_transport()
channel = transport.open_session()
channel.get_pty()
channel.set_combine_stderr(True)

cmd = "(nohup tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap) &"
channel.exec_command(cmd)
status = channel.recv_exit_status()

After I execute this code, pgrep tcpdump returns nothing.

If I remove & sign tcpdump runs correctly, but my ssh shell is blocked.

How can I run tcpdump in background correctly?

What command I've tried:

cmd = 'nohup tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap &\n'
cmd = "screen -d -m 'tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap'"
cmd = 'nohup sleep 5 && echo $(date) >> "test.log" &'

回答1:

With & you make your remote command exit instantly. The remote sshd will therefore likely (depends on implementation, but openssh does) kill all processes that were started from your command invocation. In your case, you just spawn a new process nohup tcpdump which will instantly return due to & at the end. The channel.recv_exit_status() will only block until the exit code for the & ooperation is ready which instantly is. Your code then just terminates, terminating your ssh session which will make the remote sshd kill the spawned nohup tcpdump proc. That why you end up with no tcpdump process.

Here's what you can do:

Since exec_command is going to spawn a new thread for your command, you can just leave it open and proceed with other tasks. But make sure to empty buffers every now and then (for verbose remote commands) to prevent paramiko from stalling.

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=login, password=password)
transport = ssh.get_transport()
channel_tcpdump = transport.open_session()
channel_tcpdump.get_pty()
channel_tcpdump.set_combine_stderr(True)

cmd = "tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap"        # command will never exit
channel_tcpdump.exec_command(cmd)  # will return instantly due to new thread being spawned.
# do something else
time.sleep(15)      # wait 15 seconds
_,stdout,_ = ssh.exec_command("pgrep tcpdump") # or explicitly pkill tcpdump
print stdout.read()     # other command, different shell
channel_tcpdump.close()     # close channel and let remote side terminate your proc.
time.sleep(10)