Python 如何在GNU无线电中重新连接TCP源?
如何在GNU无线电中重新连接TCP源服务器?一旦您连接了客户端一次,它就不能接受新的连接。在研究了Python 如何在GNU无线电中重新连接TCP源?,python,sockets,gnuradio,Python,Sockets,Gnuradio,如何在GNU无线电中重新连接TCP源服务器?一旦您连接了客户端一次,它就不能接受新的连接。在研究了tcp.py之后,很明显这是因为python部分只调用accept一次 以前有人在邮件列表中问过这个问题:但答案有点不令人满意,因为据说用一些“dup魔术”很容易做到 我使用文件描述符作为Python中的标识符,通过以下方式创建了一个重新连接套接字: #!/usr/bin/env python import os import socket import sys import threading
tcp.py
之后,很明显这是因为python部分只调用accept
一次
以前有人在邮件列表中问过这个问题:但答案有点不令人满意,因为据说用一些“dup魔术”很容易做到
我使用文件描述符作为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>
2015年12月18日星期五14:18:32
选择权
作者
窗口大小
类别
习俗
评论
描述
_启用
真的
_协调
(8, 8)
_轮换
0
生成\u选项
qt_-gui
身份证件
顶块
最大值
0
实时调度
运行选项
促使
跑
真的
螺纹安全设置器
标题
变量
评论
_启用
真的
_协调
(8, 160)
_轮换
0
身份证件
抽样率
价值
32000
blks2_tcp_接收器
地址
127.0.0.1
别名
评论
密切关系
_启用
真的
_协调
(696, 125)
_轮换
0
身份证件
blks2\u tcp\u接收器\u 0
类型
复杂的
服务器
真的
港口
9001
弗伦
1.
blks2_tcp_源
地址
127.0.0.1
别名
评论
密切关系
_启用
真的
_协调
(344, 136)
_轮换
0
身份证件
blks2\u tcp\u源\u 0
马克斯堡
0
米努特布夫
0
服务器
真的
类型
复杂的
港口
9000
弗伦
1.
节流阀
别名
评论
密切关系
_启用
真的
_协调
(536, 112)
_轮换
0
身份证件
阻塞\u节流阀\u 0
忽略标签
真的
马克斯堡
0
米努特布夫
0
每秒采样数
抽样率
类型
复杂的
弗伦
1.
blks2\u tcp\u源\u 0
阻塞\u节流阀\u 0
0
0
阻塞\u节流阀\u 0
blks2\u tcp\u接收器\u 0
0
0
老实说,我一直觉得tcp\u sink
和\u source
不过是不完整的黑客行为,主要是为了说明快速、基本而不是正确地做某事是多么容易;请注意版权年,至少在过去6年中,没有人真正尝试改进这种方法,这主要是因为它非常不完整。正如您可能注意到的,其中有一个事实,即只要没有连接,构造函数就会阻塞,而不是让其他块也被实例化,然后在其工作时阻塞,直到它可以使用样本为止
我不完全确定这里出了什么问题,但这很可能是一个python多线程问题——GNU无线电调度器为每个信号处理块生成一个自己的线程,在什么上下文中调用块的函数对python来说并不总是透明的
所以,第一个问题是:你需要网络还是TCP?如果您需要任何运行良好的无状态服务器,请使用UDP服务器;它们使用异步IO实现,工作非常可靠。如果您需要优雅、完整性保证的网络,请尝试zeroMQ块
假设您确实想要TCP:
<>我认为你最好的做法实际上是扔掉现有的SHILLIX块和 FielyDealthRoxSux<代码>方法,简单地处理你自己的Python或C++的Cink块中的连接。
这并不难;您似乎非常擅长编写GNU Radio python块,但作为参考(以及以后的读者),我想在简要介绍了SDR和GRC用法之后,向您介绍一下编写python块
一般说来,这都是因为
生成树外模块gr_modtool newmod
cd
添加python接收器块gr\u modtool add
修改该块以具有正确的io_签名
,并具有有意义的工作
功能,即
- 检查现有TCP连接
- 尝试发送工作调用的样本
- 如果>0,则返回发送的项目数
- 如果没有连接,则尝试建立新连接,b