Python-通过套接字与子进程通信
我希望复制Git和Rsync等程序通过SSH连接进行通信和传输数据的方式,但使用Python。据我所知,这些程序分叉并执行一个SSH命令,该命令在服务器端启动一个进程,并且通过父进程与分叉子进程的STDIN和STDOUT进行通信来实现 在C中,我看到了通过创建一个Unix套接字对(s0,s1),分叉进程,将分叉进程的stdin/stdout指向子进程上的s1,然后读取和写入父进程上的套接字s0来实现这一点 我想在Python3中做同样的事情。作为概念证明,这里是我的玩具远程shell的实现,它通过套接字发送命令并从同一套接字接收输出:Python-通过套接字与子进程通信,python,linux,python-3.x,sockets,networking,Python,Linux,Python 3.x,Sockets,Networking,我希望复制Git和Rsync等程序通过SSH连接进行通信和传输数据的方式,但使用Python。据我所知,这些程序分叉并执行一个SSH命令,该命令在服务器端启动一个进程,并且通过父进程与分叉子进程的STDIN和STDOUT进行通信来实现 在C中,我看到了通过创建一个Unix套接字对(s0,s1),分叉进程,将分叉进程的stdin/stdout指向子进程上的s1,然后读取和写入父进程上的套接字s0来实现这一点 我想在Python3中做同样的事情。作为概念证明,这里是我的玩具远程shell的实现,它通
import subprocess
import socket
ssh_cmd = 'ssh -q -T ubuntu@xxxxxxxx'
s_local, s_remote = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
ssh = subprocess.Popen(ssh_cmd, shell=True,
stdout=s_remote,
stdin=s_remote,
close_fds=True)
s_remote.close()
s_local.send('ls -l\n'.encode())
print(s_local.recv(1024).decode())
s_local.send('uname -a\n'.encode())
print(s_local.recv(1024).decode())
s_local.close()
ssh.kill()
这类作品。但是如果我将'true\n'发送到套接字,我可以使它死锁,因为'recv'正在阻塞,所以这不太好
我将web浏览器连接到SSH连接远程端上运行的命令的
stdin
和stdout
。听起来你正在尝试做类似的事情:将套接字连接到远程机器上运行的程序,以便客户端可以连接到主机/端口并使用所述远程程序
您需要做的第一件事是建立SSH连接。我在子流程中使用一个外部ssh
程序(取决于操作系统ssh
或plink
)。您可以使用classsubprocess.Popen
来实现这一点。子流程启动(外部)ssh
应用程序以连接到远程主机并运行所需的命令。然后坐在那里听它的“stdin”,并愿意回答它的“stdout”
(您可以在这里使用Python SSH实现,例如Paramiko)
在非常高的级别上(其中远程_命令
是在远端运行的东西):
这就给您留下了一个子流程,您可以通过它的stdin
、stdout
和stderr
与之交互
首先让这一部分工作。
接下来需要绑定套接字、侦听并接受连接。然后从客户端读取数据并写入服务器。我写了一个轻量级的Socat
(灵感来自)类:
您应该仔细阅读Sockets:and在这里很有用
然后,您可以使用它连接到远程\u命令
:
Socat( ('localhost', 8080), sproc)
缺少一些位
您会注意到socat
类接受了一个流
(与我的示例不同),该流具有write
和readline
方法。我实际上将SSH连接封装在一个类中,但我将把它留给读者作为练习
(基本上是一个类流
,它包含存储过程
,并提供write
和readline
方法-有效地sproc.stdin.write()
和sproc.stdout.readline()
-你明白了!)
此外,您还需要一个协议来允许远程_命令
发出传输结束的信号。我使用了ASCIIEOT
字符,我的远程程序在响应结束时发送该字符。socat
使用它来关闭客户端连接并接受新的连接。根据您的用例,您需要制定一个适合您的协议
最后
所有这些都可以改进。上面的内容是我的第一个剪辑,因为它很容易看到内部工作。此后,我将其扩展为在线程中运行accept循环,并优雅地处理断开连接等
但希望以上所述是一个合理的起点。您试图做的是非常明智的。您可能需要调查
pexpect
模块。它是为这类事情量身定做的:驱动交互式应用程序。看到一个好的开始。它还能够在您的交互上设置超时,以防您期望响应但没有响应。您的示例代码将stdin和stdout都设置为s_remote。
import socket
class Socat(object):
EOT = '\004\r\n'
def __init__(self, binding, stream, eot = EOT):
self.stream = stream
self.eot = eot
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind(binding)
self.socket.listen(5)
while True:
print "waiting for connection"
(clientsocket, address) = self.socket.accept()
print "connection from %s:%s" % address
data = clientsocket.recv(1024)
self.stream.write(data)
while data:
data = self.stream.readline()
if data:
print "read %s bytes" % len(data)
if data == self.eot:
print "read termination signature"
clientsocket.close()
data = None
else:
clientsocket.send(data)
Socat( ('localhost', 8080), sproc)