我正在为UDP应用程序编写测试工具(TH),打开通往UDP应用程序另一个实例的隧道。要通过隧道发送内容,每个UDP应用程序都有一个与读取/写入模式相关联的命名管道(相对于TUN接口,我将来会使用它)。每个UDP应用程序都有几个子进程,TH在不同的线程中启动UDP应用程序作为子进程,以及通过子进程中的管道发送数据。这是一个混乱,但我希望它首先在一个简单的案例上工作,因为我想最终建立超过5个应用程序的隧道。
2个问题:
以下是来自TH的隧道数据流:
当然,这根本不起作用。当我通过fifo1从TH发送几条消息到app#1时,只有第一条消息通过app#1。此消息通过UDP隧道正确传输到app#2。 App#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: 在app#1一侧,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:我的理论是TH在它有任何内容之前尝试读取管道。但这没有意义,因为我在接收fifo2数据时做了一段时间的循环。我尝试了一些更简单的东西,但没有用。
测试工具的相关部分:
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应用程序的选择循环以及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
# ...
答案 0 :(得分:1)
您可能看不到任何内容,因为数据卡在stdio缓冲区中;尝试在打印后添加fifo.flush()
。一般来说,应该警惕混合缓冲IO和选择。
最好从print
和file.readline()
切换到os.write()
和os.read()
,它们不会缓冲,并且具有更可预测的行为wrt {{1 }}