我有一个应用程序,软件定义无线电,在一个端口上广播UDP数据包,告诉听众已经设置了什么频率和解调模式(等等).
我编写了一个演示python客户端(下面的代码)来监听端口,并将相应数据包中的信息转储到控制台.
这些都在OSX 10.6,Snow Leopard下运行.他们在那里工作.
我的问题是:Python应用程序必须在无线电应用程序之前启动,或者在绑定期间声称端口已在使用(ERRNO 47),我不明白为什么.无线电应用正在广播UDP; 当然,我想容纳多个听众 - 这就是广播的想法,或者至少,所以我想.
所以这里是Python代码(由于堆栈溢出真的很愚蠢"make-it-code"缩进,缩进有点混乱,但我保证你没关系):
#!/usr/bin/python
import select, socket
# AA7AS - for SdrDx UDP broadcast
# this is a sample python script that captures the UDP messages
# that are coming from SdrDx. SdrDx tells you what frequency and
# mode it has been set to. This, in turn, would be used to tell
# another radio to tune to that frequency and mode.
# UDP packet from SdrDx is zero terminated, but receiving the
# packet makes it seem like the string contains zeros all the
# way out to the 1024th character. This function extracts a
# python string up to the point where it hits the first zero,
# then returns that string.
# -----------------------------------------------------------
def zeroterm(msg):
counter = 0;
for c in msg:
if ord(c) != 0:
counter += 1
strn = msg[:counter]
return strn
port = 58083 # port where we expect to get a msg
bufferSize = 1024 # room for message
# Create port to listen upon
# --------------------------
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.bind(('', port))
except:
print 'failure to bind'
s.close()
raise
s.setblocking(0)
# Listen for messages
# -------------------
looping = True
while looping:
try:
result = select.select([s],[],[])
except: # you can kill the client here with control-c in its shell
s.close() # must close socket
print 'Closing, exception encountered during select' # warn
raise SystemExit # and quit
msg = result[0][0].recv(bufferSize) # actually fetch the UDP data
msg = zeroterm(msg) # convert content into python string
# in next line, [] contain optional repeats
# message format is keyword:data[|keyword:data]
# where from 1...n keyword:data pairs may appear, up to 1024 bytes
# ----------------------------------------------------------------
try:
msgs = msg.split('|') # can be more than one message in packet
except: # failed to split
msgs = [] # on the other hand, can just be one. :)
msgs.append(msg) # so build array with that one.
for m in msgs: # now, for every message we have
keyw,data = m.split(':') # break into keyword and data
print keyw + "-->" + data # you'd do something with this
if keyw == "closing": # Our client terminates when SdrDx does
looping = False # loop stops
s.close() # must close socket
print 'Normal termination'
Run Code Online (Sandbox Code Playgroud)
作为参考,这是发送UDP消息的Qt代码:
建立:
bcast = new QHostAddress("192.168.1.255");
if (bcast)
{
udpSocketSend = new QUdpSocket(0);
if (udpSocketSend)
{
udpSocketSend->bind(*bcast, txudp);
}
}
Run Code Online (Sandbox Code Playgroud)
广播:
if (udpSocketSend)
{
QByteArray *datagram = new QByteArray(1024,0); // datagram is full of zeroes
strcpy(datagram->data(),msg); // except where text message is in it at beginning
udpSocketSend->writeDatagram(*datagram, QHostAddress::Broadcast,txudp); // send
}
Run Code Online (Sandbox Code Playgroud)
您正在尝试绑定同一个端口,两次.
您在发件人中绑定一次:
if (udpSocketSend)
{
udpSocketSend->bind(*bcast, txudp);
}
Run Code Online (Sandbox Code Playgroud)
并再次在接收器
s.bind(('', port))
Run Code Online (Sandbox Code Playgroud)
由于它们在同一台机器上运行,因此出现错误.
除非您关心源端口是什么,否则您不需要bind()在发送方上,只需发送它,堆栈将选择适当的输出源端口号.对于发送方,当您传输UDP数据报时,您指定destination(udpSocketSend->writeDatagram(...)),并bind实际确定传出数据报的来源.如果你不这样做bind,那很好,堆栈将为你分配一个端口.
如果您确实关心源端口是什么,那么我建议您为传出源端口和传入目标端口使用不同的端口号.然后你就可以毫无问题地绑定发送者和接收者.
最后,可以选择设置SO_REUSEADDR套接字选项(使用您正在使用的任何语言).如果要在同一台计算机上运行多个客户端,则必须这样做,因为所有客户端都必须绑定到同一个地址.但是,我不确定这个套接字选项是否是跨平台的(*nix工作正常),我认为上述建议更好.
| 归档时间: |
|
| 查看次数: |
9240 次 |
| 最近记录: |