简体   繁体   English

我如何将cmd1的stdout输出到扭曲的cmd2的stdin中,其中cmd1进程在扭曲的客户端上,而cmd2是服务器上的进程?

[英]How do I pipe stdout of cmd1 to stdin of cmd2 in twisted where cmd1 process is on a twisted client and cmd2 is a process on a server?

How do i connect the stdout of a spawnProcess to the stdin of another spawnProcess in twisted, where spawnProcess with the stdout is on the client and the stdin spawnprocess on the server? 我如何将spawnProcess的stdout连接到另一个扭曲的spawnProcess的stdin中,其中带有stdout的spawnProcess在客户端上,而stdin spawnprocess在服务器上? The CLI command in bash is btrfs send @mysubvol | btrfs receive /some/path/ bash中的CLI命令是btrfs send @mysubvol | btrfs receive /some/path/ btrfs send @mysubvol | btrfs receive /some/path/ . btrfs send @mysubvol | btrfs receive /some/path/ With rfd, wrd = os.pipe() I managed to pipe process1 to process2 on the server side. 使用rfd, wrd = os.pipe()我设法在服务器端将process1传递给process2。 (Now I want to pipe it from the client to the server instead). (现在,我想将其从客户端管道传输到服务器)。 Following code shows the processes piped on the same side: 以下代码显示了通过同一方传递的进程:

Following code 以下代码

    from twisted.internet import protocol
from twisted.internet import reactor
import os


class Writer(protocol.ProcessProtocol):
    def connectionMade(self):
        print "Writer -- connection made"
        self.transport.closeChildFD(0)
    def childDataReceived(self, fd):
        pass
    def processEnded(self, status):
        pass


class Reader(protocol.ProcessProtocol):
    def __init__(self):
        pass
    def connectionMade(self):
        print "Reader -- connection made"
        pass
    def childDataReceived(self, fd):
        print "Reader -- childDataReceived"
    def processEnded(self, status):
        print "process ended, got:"

def test2():
    rfd, wfd = os.pipe()
    p1 = reactor.spawnProcess(Writer(), "btrfs", ["btrfs", "send", "/@mySubvol"],env=None, childFDs={0:"w", 1: wfd })
    p2 = reactor.spawnProcess(Reader(), "btrfs", ["btrfs", "receive", "/subvolContainer/"], env=None, childFDs={0: rfd, 1: "r"})
    os.close(rfd)
    os.close(wfd)
    reactor.run()
test2()

I tried: 我试过了:

server.py server.py

from twisted.internet.protocol import Protocol, Factory, ClientFactory
from twisted.internet import protocol
from twisted.internet import reactor
import os


class Reader(protocol.ProcessProtocol):
    def __init__(self):
        pass
    def connectionMade(self):
        print "Reader -- connection made"
        pass
    def childDataReceived(self, fd):
        print "Reader -- childDataReceived"
    def processEnded(self, status):
        print "process ended, got:"


class EchoClientFactory(ClientFactory):
    protocol = Reader
    def clientConnectionFailed(self, connector, reason):
        print 'connection failed:', reason.getErrorMessage()
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print 'connection lost:', reason.getErrorMessage()
        reactor.stop()

def main():
    f = Factory()
    reactor.listenTCP(8000, f)
    rfd = os.pipe()
    p2 = reactor.spawnProcess(Reader(), "btrfs", ["btrfs", "receive", "/"], env=None, childFDs={0: rfd, 1: "r"})
    os.close(rfd)
    reactor.run()
if __name__ == '__main__':
    main()

client.py client.py

from twisted.internet import reactor
from twisted.internet import protocol
import sys
import os


class Writer(protocol.ProcessProtocol):
    def connectionMade(self):
        print "Writer -- connection made"
        self.transport.closeChildFD(0)
    def childDataReceived(self, fd):
        pass
    def processEnded(self, status):
        pass


class EchoClientFactory(protocol.ClientFactory):
    protocol = Writer
    def clientConnectionFailed(self, connector, reason):
        print 'connection failed:', reason.getErrorMessage()
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print 'connection lost:', reason.getErrorMessage()
        reactor.stop()

def main():
    factory = EchoClientFactory()
    rfd, wfd = os.pipe()
    p1 = reactor.spawnProcess(Writer(), "btrfs", ["btrfs", "send", "/home/philipp/testEnv/a2a/@a2"], env=None, childFDs={0:"w", 1: wfd })
    reactor.connectTCP('localhost', 8000, factory)
    os.close(wfd)
    reactor.run()
if __name__ == '__main__':
    main()

Obviously my attempt is wrong, because the server does not know about the client's stdout pipe, but I don't know how to pipe the client's spawnProcess stdout to the server. 显然,我的尝试是错误的,因为服务器不了解客户端的stdout管道,但是我不知道如何将客户端的spawnProcess stdout管道到服务器。


Update 01: 更新01:

Following Jean-Paul's answer I created two protocols on the client and server ( ProcessProtocol and TCP-Protocol on each side). 按照Jean-Paul的回答,我在客户端和服务器上创建了两个协议(在每一侧分别为ProcessProtocolTCP-Protocol )。 I could successfully send a snapshot from the client to the server. 我可以成功地将快照从客户端发送到服务器。 On the client I had to start the ProcessProtocol with the instance of my TCP-Protocol , so that they are both interconnected. 在客户端上,我必须使用TCP-Protocol实例启动ProcessProtocol ,以便它们相互连接。 See: http://twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#HowdoImakeinputononeconnectionresultinoutputonanother 请参阅: http//twistedmatrix.com/trac/wiki/FrequentlyAskedQuestions#HowdoImakeinputononeconnectionresultinoutputanotherother

client.py client.py

    from twisted.internet.protocol import Protocol, Factory, ClientFactory, ProcessProtocol
from twisted.internet import reactor
import sys
import os


class Writer(Protocol):

    def connectionMade(self):  # Called when a connection is made
        print "connec made"
        proc = MyProcessProtocol(self)
        p1 = reactor.spawnProcess(proc, "btrfs", ["btrfs", "send", "/home/user/testEnv/a2a/@a2"])


class EchoClientFactory(ClientFactory):

    protocol = Writer

    def clientConnectionFailed(self, connector, reason):
        print 'connection failed:', reason.getErrorMessage()
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print 'connection lost:', reason.getErrorMessage()
        reactor.stop()


class MyProcessProtocol(ProcessProtocol):
    def __init__(self, instance):
        self.w = instance

    def outReceived(self, data):  # Some data was received from stdout
        self.w.transport.write(data)  # Write some data to the physical connection, in sequence, in a non-blocking fashion


def main():
    factory = EchoClientFactory()
    reactor.connectTCP('localhost', 8000, factory)
    reactor.run()
if __name__ == '__main__':
    main()

server.py server.py

    from twisted.internet.protocol import Protocol, Factory, ClientFactory, ProcessProtocol, ServerFactory
from twisted.internet import reactor
import os


class Reader(Protocol):

    def connectionMade(self):
        print "connected"
        self.r2 = Reader2()
        p1 = reactor.spawnProcess(self.r2, "btrfs", ["btrfs", "receive", "/"])

    def dataReceived(self, data):
        print "dataReceived"
        self.r2.transport.write(data)


class Reader2(ProcessProtocol):

    def connectionMade(self):
        print "connectionMade!"

    def processEnded(self, reason):
        print "quitting"


def main():
    f = ServerFactory()
    f.protocol = Reader
    reactor.listenTCP(8000, f)
    reactor.run()
if __name__ == '__main__':
    main()

You cannot set up a pipe across machines. 您不能跨机器设置管道。 You can't do this in a shell either. 您也不能在shell中执行此操作。 The shell expression: 外壳表达式:

btrfs send @mysubvol | btrfs发送@mysubvol | btrfs receive /some/path/ btrfs接收/ some / path /

runs two btrfs processes on a single machine with a pipe connecting them. 在一机器上运行两个btrfs进程,并用管道将它们连接起来。

Pipes are purely local. 管道纯粹是本地的。 They cannot be shared across machines. 它们不能在计算机之间共享。 For this, you need something else. 为此,您还需要其他东西。 For example, a TCP connection. 例如,TCP连接。

You have taken a couple steps in the right direction. 您已朝正确的方向迈出了几步。 Your server starts a TCP server. 您的服务器启动一个TCP服务器。 Your client attempts to establish a new connection to that server. 您的客户端尝试建立与该服务器的新连接。

But your server doesn't define any behavior for handling connections it accepts. 但是您的服务器没有定义任何行为来处理它接受的连接。 And your client uses a ProcessProtocol to define its behavior - when a TCP connection is not a process. 并且您的客户端使用ProcessProtocol定义其行为-当TCP连接不是进程时。

One idea you may have missed is that on your client you will need two protocols. 您可能会错过的一个想法是,在您的客户端上,您将需要两个协议。 One protocol is connected to the btrfs send process and reads its stdout. 一种协议连接到btrfs send进程并读取其stdout。 Another protocol is connected to your server and can write that btrfs send output to the TCP connection. 另一个协议已连接到您的服务器,并且可以写成btrfs send输出btrfs send到TCP连接。

And your server will need two protocols as well. 您的服务器也将需要两个协议。 One of them handles the connection from the client and reads the data the client is writing to that connection. 其中之一处理来自客户端的连接,并读取客户端正在写入该连接的数据。 The other is connected to a btrfs receive process and writes the data read from the TCP connection to that process's stdin. 另一个连接到btrfs receive进程,并将从TCP连接读取的数据写入该进程的stdin。

You've found the childFDs feature of spawnProcess which is a nice local optimization. 如果你找到了childFDs的特点spawnProcess这是一个很好的局部优化。 And while you can technically use it to help you connect two processes on two different machines, it involves extra steps that you probably don't want to bother with (at least not until you're comfortable with a "regular" forwarder). 尽管可以从技术上使用它来帮助您连接两台不同机器上的两个进程,但是它涉及到一些您可能不想打扰的额外步骤(至少直到您对“常规”转发器感到满意为止)。

Instead, you just want a handful of protocols that receive data from objects nearer the sending side of your setup (via childDataReceived and dataReceived) and hand it off to objects nearer the receiving side of your setup (via transport.write). 取而代之的是,您只需要一些协议,即可从设置的发送方附近的对象(通过childDataReceived和dataReceived)接收数据,然后将其传递给设置的接收方附近的对象(通过transport.write)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM