【问题标题】:Python and UDP listeningPython 和 UDP 监听
【发布时间】:2012-06-04 20:24:46
【问题描述】:

我有一个应用程序,软件定义无线电,它在一个端口上广播 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'

作为参考,这里是发送 UDP 消息的 Qt 代码:

设置:

bcast = new QHostAddress("192.168.1.255");
if (bcast)
{
    udpSocketSend = new QUdpSocket(0);
    if (udpSocketSend)
    {
        udpSocketSend->bind(*bcast, txudp);
    }
}

广播:

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
}

【问题讨论】:

  • 这两个应用在同一台机器上运行,是吗?
  • 您需要修复缩进。在try: 之后,不能有与try: 语句具有相同缩进级别的行。
  • @jedwards,是的。 ThiefMaster:正如我在 Python 代码上方明确说过的,stackoverflow 的格式弄乱了缩进。代码缩进正确。不用担心。

标签: python udp


【解决方案1】:

你试图绑定同一个端口,两次。

你在发件人中绑定一次:

if (udpSocketSend)
{
    udpSocketSend->bind(*bcast, txudp);
}

在接收器处再次

s.bind(('', port))

而且由于它们在同一台机器上运行,因此您会遇到错误。

除非你关心源端口是什么,否则你不需要在发送者上bind(),只需发送它,堆栈就会选择一个合适的传出源端口号。对于发送方,当您传输 UDP 数据报时,您指定目的地 (udpSocketSend->writeDatagram(...)),而bind 实际上决定了传出数据报的。如果你不bind,没关系,堆栈会给你分配一个端口。

如果您确实关心源端口是什么,那么我建议您为传出源端口和传入目标端口使用不同的端口号。然后你就可以毫无问题地绑定发送者和接收者了。

最后,可以选择设置SO_REUSEADDR 套接字选项(无论您使用什么语言)。如果您想在同一台机器上运行多个客户端,这将是必要的,因为所有客户端都必须绑定到同一个地址。但是,我不确定这个套接字选项是否是跨平台的(*nix 工作正常),我认为上述建议更好。

【讨论】:

  • +1,但为了完全明确,在 TCP/IP 通信中,您几乎从不关心源端口是什么。几乎您唯一关心的就是您是否尝试协商一组特定的防火墙规则。
  • Russell:这是 UDP。不是 TCP。 @jedwards:我需要(单个)应用程序发送可以被多个客户端接收的广播。我需要客户端(可能其中几个)能够向应用程序发送消息。在任何情况下,我都不希望用户实际上必须进行任何设置。广播的想法似乎适合两端(似乎没有其他东西真正适合。)我错了吗?
猜你喜欢
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
  • 2017-12-24
相关资源
最近更新 更多