如何在GNU無線電中重新連接TCP源服務器?一旦連接了一個客戶端,它就不能接受新的連接。在研究了tcp.py
之後,很明顯這是因爲python部分只調用了accept
一次。如何在GNU無線電中使TCP源重新連接?
以前在郵件列表上詢問過這個問題:https://lists.gnu.org/archive/html/discuss-gnuradio/2010-04/msg00501.html但是答案有點不滿意,因爲它被認爲很容易處理一些「重複魔法」。
我設法使用文件描述符在Python通過以下方式標識做出重新連接插座:
#!/usr/bin/env python
import os
import socket
import sys
import threading
def get_server_socket_and_fd():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 9999))
s.listen(1)
print "waiting for client connection on port 9999"
cs, address = s.accept()
return s, os.dup(cs.fileno())
class StoppableThread(threading.Thread):
def __init__(self):
super(StoppableThread, self).__init__()
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
class SocketWatcher(StoppableThread):
def __init__(self, server_socket, fd):
super(SocketWatcher, self).__init__()
self.setDaemon(True)
self._fd = fd
self._server_socket = server_socket
def run(self):
print "WWW: starting watcher on fd = {}".format(self._fd)
while not self.stopped():
#print "WWW: creating socket object from fd = {}".format(self._fd)
s = socket.fromfd(self._fd, socket.AF_INET, socket.SOCK_STREAM)
while not self.stopped():
print "WWW: trying to peek for new data"
data = s.recv(1024, socket.MSG_PEEK)
print "WWW: msg peek returned: {} bytes".format(len(data))
if len(data) == 0:
print "WWW: EOF? closing socket"
s.close()
print "WWW: waiting for new connection..."
cs, address = self._server_socket.accept()
print "WWW: new connection! fileno = {}".format(cs.fileno())
print "WWW: duplicating this client socket fd into the old one"
os.dup2(cs.fileno(), self._fd)
break
print "WWW: thread stopped, exiting run method"
server_socket, client_fd = get_server_socket_and_fd()
watcher = SocketWatcher(server_socket, client_fd)
watcher.start()
try:
while True:
s = socket.fromfd(client_fd, socket.AF_INET, socket.SOCK_STREAM)
data = s.recv(1024)
if len(data) > 0:
print " data received: {} bytes".format(len(data))
print repr(data)
except (KeyboardInterrupt, SystemExit):
print "stopping program..."
watcher.stop()
sys.exit()
這就像預期:啓動python腳本,連接到該端口,寫的東西,靠近連接,打開另一個連接,寫更多的東西,並注意到它們繼續被打印。
但是,當我嘗試將其整合到GNU收音機中時:它不起作用。這是我最好的嘗試:
#
# Copyright 2009 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from gnuradio import gr, blocks
import socket
import os
import threading
class StoppableThread(threading.Thread):
def __init__(self):
super(StoppableThread, self).__init__()
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
class SocketWatcher(StoppableThread):
def __init__(self, server_socket, fd):
super(SocketWatcher, self).__init__()
self.setDaemon(True)
self._fd = fd
self._server_socket = server_socket
def run(self):
while not self.stopped():
s = socket.fromfd(self._fd, socket.AF_INET, socket.SOCK_STREAM)
while not self.stopped():
data = s.recv(1024, socket.MSG_PEEK)
if len(data) == 0:
print "EOF detected. Closing socket and waiting for new connection..."
s.close()
cs, address = self._server_socket.accept()
print "got new connection!"
os.dup2(cs.fileno(), self._fd)
break
def _get_sock_fd(addr, port, server):
"""
Get the file descriptor for the socket.
As a client, block on connect, dup the socket descriptor.
As a server, block on accept, dup the client descriptor.
Args:
addr: the ip address string
port: the tcp port number
server: true for server mode, false for client mode
Returns:
the file descriptor number
"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server:
sock.bind((addr, port))
sock.listen(1)
clientsock, address = sock.accept()
return os.dup(clientsock.fileno()), sock
else:
sock.connect((addr, port))
return os.dup(sock.fileno()), sock
class tcp_source(gr.hier_block2):
def __init__(self, itemsize, addr, port, server=True):
#init hier block
gr.hier_block2.__init__(
self, 'tcp_source',
gr.io_signature(0, 0, 0),
gr.io_signature(1, 1, itemsize),
)
if not server:
raise NotImplementedError
fd, server_socket = _get_sock_fd(addr, port, server)
watcher = SocketWatcher(server_socket, fd)
watcher.start()
self.connect(blocks.file_descriptor_source(itemsize, fd), self)
class tcp_sink(gr.hier_block2):
def __init__(self, itemsize, addr, port, server=False):
#init hier block
gr.hier_block2.__init__(
self, 'tcp_sink',
gr.io_signature(1, 1, itemsize),
gr.io_signature(0, 0, 0),
)
fd, _ = _get_sock_fd(addr, port, server)
self.connect(self, blocks.file_descriptor_sink(itemsize, fd))
我確實看到在命令行上:
EOF detected. Closing socket and waiting for new connection...
got new connection!
這表明檢測EOF是成功的,但是,一旦我重新連接被接受,但無論我寫的到套接字不會出現在另一端。我使用一個簡單的GNU廣播程序來測試它,包括一個TCP源(我的版本),一個節流閥和一個TCP接收器。
<?xml version='1.0' encoding='utf-8'?>
<?grc format='1' created='3.7.8'?>
<flow_graph>
<timestamp>Fri Dec 18 14:18:32 2015</timestamp>
<block>
<key>options</key>
<param>
<key>author</key>
<value></value>
</param>
<param>
<key>window_size</key>
<value></value>
</param>
<param>
<key>category</key>
<value>Custom</value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>description</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 8)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>generate_options</key>
<value>qt_gui</value>
</param>
<param>
<key>id</key>
<value>top_block</value>
</param>
<param>
<key>max_nouts</key>
<value>0</value>
</param>
<param>
<key>realtime_scheduling</key>
<value></value>
</param>
<param>
<key>run_options</key>
<value>prompt</value>
</param>
<param>
<key>run</key>
<value>True</value>
</param>
<param>
<key>thread_safe_setters</key>
<value></value>
</param>
<param>
<key>title</key>
<value></value>
</param>
</block>
<block>
<key>variable</key>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(8, 160)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>samp_rate</value>
</param>
<param>
<key>value</key>
<value>32000</value>
</param>
</block>
<block>
<key>blks2_tcp_sink</key>
<param>
<key>addr</key>
<value>127.0.0.1</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(696, 125)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blks2_tcp_sink_0</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>server</key>
<value>True</value>
</param>
<param>
<key>port</key>
<value>9001</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blks2_tcp_source</key>
<param>
<key>addr</key>
<value>127.0.0.1</value>
</param>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(344, 136)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blks2_tcp_source_0</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>server</key>
<value>True</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>port</key>
<value>9000</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<block>
<key>blocks_throttle</key>
<param>
<key>alias</key>
<value></value>
</param>
<param>
<key>comment</key>
<value></value>
</param>
<param>
<key>affinity</key>
<value></value>
</param>
<param>
<key>_enabled</key>
<value>True</value>
</param>
<param>
<key>_coordinate</key>
<value>(536, 112)</value>
</param>
<param>
<key>_rotation</key>
<value>0</value>
</param>
<param>
<key>id</key>
<value>blocks_throttle_0</value>
</param>
<param>
<key>ignoretag</key>
<value>True</value>
</param>
<param>
<key>maxoutbuf</key>
<value>0</value>
</param>
<param>
<key>minoutbuf</key>
<value>0</value>
</param>
<param>
<key>samples_per_second</key>
<value>samp_rate</value>
</param>
<param>
<key>type</key>
<value>complex</value>
</param>
<param>
<key>vlen</key>
<value>1</value>
</param>
</block>
<connection>
<source_block_id>blks2_tcp_source_0</source_block_id>
<sink_block_id>blocks_throttle_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
<connection>
<source_block_id>blocks_throttle_0</source_block_id>
<sink_block_id>blks2_tcp_sink_0</sink_block_id>
<source_key>0</source_key>
<sink_key>0</sink_key>
</connection>
</flow_graph>