Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-通过套接字与子进程通信_Python_Linux_Python 3.x_Sockets_Networking - Fatal编程技术网

Python-通过套接字与子进程通信

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的实现,它通

我希望复制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'正在阻塞,所以这不太好

  • 在网络编程中,这是明智的/常见的做法吗
  • 使用不会死锁的Python3标准库实现这一点的更惯用方法是什么

  • 我将web浏览器连接到SSH连接远程端上运行的命令的
    stdin
    stdout
    。听起来你正在尝试做类似的事情:将套接字连接到远程机器上运行的程序,以便客户端可以连接到主机/端口并使用所述远程程序

    您需要做的第一件事是建立SSH连接。我在子流程中使用一个外部
    ssh
    程序(取决于操作系统
    ssh
    plink
    )。您可以使用class
    subprocess.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()
    -你明白了!)

    此外,您还需要一个协议来允许
    远程_命令
    发出传输结束的信号。我使用了ASCII
    EOT
    字符,我的远程程序在响应结束时发送该字符。
    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)