带有IPC和子进程的python命名管道

带有IPC和子进程的python命名管道,python,ipc,named-pipes,Python,Ipc,Named Pipes,我正在为一个UDP应用程序编写一个测试工具TH,它打开了一个到UDP应用程序另一个实例的隧道。为了通过隧道发送内容,每个UDP应用程序都有一个与之关联的命名管道(读+写模式)和一个TUN接口,我将在将来使用它。每个UDP应用程序都有几个子进程,TH在不同线程中将UDP应用程序作为子进程启动,并通过子进程中的管道发送数据。这真是一团糟,但我想先让它在一个简单的案例中发挥作用,因为我想最终在5+个应用程序上构建隧道 2个问题: 第一个应用程序上的Select loop未获取TH发送的所有消息-仅第一

我正在为一个UDP应用程序编写一个测试工具TH,它打开了一个到UDP应用程序另一个实例的隧道。为了通过隧道发送内容,每个UDP应用程序都有一个与之关联的命名管道(读+写模式)和一个TUN接口,我将在将来使用它。每个UDP应用程序都有几个子进程,TH在不同线程中将UDP应用程序作为子进程启动,并通过子进程中的管道发送数据。这真是一团糟,但我想先让它在一个简单的案例中发挥作用,因为我想最终在5+个应用程序上构建隧道

2个问题:

第一个应用程序上的Select loop未获取TH发送的所有消息-仅第一个。选择此选项是否不会在文件每次有新内容/准备读取时通知?我目前使用pipe.readline,更改为pipe.readlines会获得大部分消息,但不是全部消息。详见下文。 在第二个应用程序中,我尝试将接收到的UDP数据写入到与第一个不同的管道中。他永远得不到数据。 以下是通过隧道从TH传输的数据流:

第次打印>>fifo1,foo fifo1 UDP应用程序1接收fifo1,发送UDP数据包 UDP隧道 UDP应用程序2接收UDP数据包,发送fifo2 fifo2 TH fifo2.readline 当然,这根本不起作用。当我通过fifo1从TH向应用程序1发送多条消息时,只有第一条消息可以发送到应用程序1。此消息通过UDP隧道正确传输到应用程序2。应用程序2写入fifo2,但在TH中,我在fifo2中没有看到任何内容。为了说明这一点,我在运行测试线束时包含了控制台输出

Sending data one way over tunnel...
rxDataFifo: reading from pipe
# Here we start sending messages (hello 0, hello 1, hello 2) via fifo1
i= 0
i= 1
i= 2
txDataFifo: finished # Now we are finished sending
handleFifoData: hello 0 # first message received on UDP app #1
UDP ('127.0.0.1', 9000):  fde04a5a1de6d473b70c184e5e981279hello 0 # Here's the message app #2 recv via UDP
...writing out to fifo! hello 0 # And app #2 write out to fifo2 (or should, at least)
# Nothing received from fifo2 on test harness!??
问题1: 在app1端,select循环不会在每次写入管道时触发多个可读事件。如果不是从管道中读取一行,而是读取所有可用的行,那么我会得到最后两条消息,但不是第一条

Sending data one way over tunnel...
rxDataFifo: reading from pipe
i= 0
i= 1
i= 2
txDataFifo: finished
handleFifoData: hello 1
handleFifoData: hello 2
UDP ('127.0.0.1', 9000):  e3270c47214147ae3698aeecc13e2acehello 1
tunnel data: hello 1
...writing out to fifo! hello 1
UDP ('127.0.0.1', 9000):  e3270c47214147ae3698aeecc13e2acehello 2
tunnel data: hello 2
...writing out to fifo! hello 2
问题2:我的理论是,它试图在管道有任何内容之前读取管道。但这没有意义,因为我在接收fifo2数据时做了一个while循环。我试过一些简单的东西,但没用

测试线束的相关部分:

def main():
    # Create pipes for each process we want to launch
    # NOTE: These pipes are passed to the multiprocessing.Process and subprocess.call
    # that we use to launch the UDP apps
    tmpdir = tempfile.mkdtemp()
    pipe0 = os.path.join(tmpdir, 'pipe0')
    pipe1 = os.path.join(tmpdir, 'pipe1')
    try:
        os.mkfifo(pipe0)
        os.mkfifo(pipe1)
    except OSError, e:
        print "Failed to create FIFO: %s" % e

    #...

    queue = Queue() # this where output goes
    num_msg = 10 # number of messages to send over tunnel
    txFifo = Process(target=txDataFifo, args=(pipe0, queue, num_msg))
    rxFifo = Process(target=rxDataFifo, args=(pipe1, queue))
    rxFifo.start()
    txFifo.start()

def txDataFifo(pipe_name, queue, num_msg):
    fifo = open(pipe_name, 'r+b')
    # print >> fifo, "hello over named pipe" # write stuff to fifo


    for i in range(0, 3):
        print "i=",i
        print >> fifo, "hello "+str(i)

    fifo.close()
    print "txDataFifo: finished"

def rxDataFifo(pipe_name, queue):
    print "rxDataFifo: reading from pipe"
    fifo = open(pipe_name, 'w+b')
    while True:
        data = fifo.readline()
        print 'rxDataFifo:', data
        queue.put(data)
    fifo.close()
    print "txDataFifo: reading from pipe"
UDP应用程序的select循环以及UDP和命名管道数据的处理程序:

def listen (self, ipaddress, udpport, testport, pipe_filename):
    # ...
    inputs = [sock, self.pipe] # stuff we read
    outputs = [] # stuff we expect to write

    # Set up the named pipe that we use to simulate the TUN interface
    # and use to communicate with the test harness
    fifo = None
    if pipe_filename:
        print "Opening pipe="+pipe_filename+" for IPC with test harness"
        fifo = open(pipe_filename, 'r+b')
        inputs.append(fifo)

    while inputs:
        readable, writable, exceptional = select.select(inputs, outputs, inputs)

        for event in readable:
            if fifo and event is fifo:
                # Handle data from test harness simulating TUN (via pipe)
                self.handleFifoData(sock, fifo)
            if event is sock:
                # Handle tunnel/setup request data
                self.handleUDPData(sock, fifo)
            if event is self.pipe:
                # Handle commands from the UI in the other process (IPC)
                data = self.pipe.recv()
                print "pipe event", data
                if data[0] == 'open':
                    # NOTE: For open command, data[1] and data[2] are
                    # an IP address and port, respectively
                    connId = self.generateConnId()
                    msg = connId + 'setup'
                    sock.sendto(msg, (data[1], data[2]))
                    self.mySetup[connId] = SetupInfo(data[1], data[2])
        # Handle exceptional?    

def handleFifoData (self, sock, fifo, ):
    # Send data from sockTest to sock
    data = fifo.readline().rstrip()

    print "handleFifoData:", data
    for peerId in self.tunnels:
        # TODO: perhaps FIFO message should be parsed json, so we know which client to send them to?
        peer = self.tunnels[peerId]
        msg = peerId + data
        sock.sendto(msg, (peer.address, peer.port))

def handleUDPData (self, sock, fifo): # reads a tuple 
    (data, addr) = sock.recvfrom(1024)
    print "UDP "+str(addr)+": ", data

    # ...
    elif peerId in self.tunnels: # We are functioning as a relay for this node
        # NOTE: This is where TUN interface forwarding would happen
        print "tunnel data:", data
        if fifo:
            print "...writing out to fifo!", data
            print >> fifo, data+'\n'
        return
    # ...

您可能什么也看不到,因为数据被困在stdio缓冲区中;尝试在打印后添加fifo.flush。一般来说,应该注意混合缓冲IO和select


最好从print和file.readline切换到os.write和os.read,这两个选项没有缓冲区,并且在wrt select中有更可预测的行为。

您可能什么也看不到,因为数据被卡在stdio缓冲区中;尝试在打印后添加fifo.flush。一般来说,我会小心混合缓冲IO和select。我建议您从print和file.readline切换到os.write和os.read,它们不缓冲,而且wrt select的行为更可预测。此外,如果缺少换行符,print已经附加了一个换行符,因此您可能希望避免添加“\n”,或者更好的做法是,避免打印优先于sys.stdout.write,或者如上所述,os.write.将所有内容转换为os.open/read/write非常有效,谢谢!我之前试过fifo.flush,但没用。我还尝试过使用python-u启动选项,但也没有成功——我的印象是强迫所有东西都不受缓冲。好的,我已经回复了上面的评论作为答案。