8

私はアプリ、ソフトウェア無線を持っています。これは、ポートでUDPパケットをブロードキャストし、リスナーにどの周波数と復調モードが設定されているかを通知します(特に)。

ポートをリッスンし、適切なパケットの情報をコンソールにダンプするデモPythonクライアント(以下のコード)を作成しました。

これらは両方ともOSX10.6、SnowLeopardで実行されています。彼らはそこで働きます。

私が抱えている質問/問題は、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
}
4

1 に答える 1

7

同じポートを2回バインドしようとしています。

送信者で一度バインドします。

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

そして再び受信機で

s.bind(('', port))

また、これらは同じマシンで実行されているため、エラーが発生します。

送信元ポートが何であるかを気にしない限りbind()、送信者に送信する必要はありません。送信するだけで、スタックは適切な送信元ポート番号を選択します。送信者の場合、UDPデータグラムを送信するときに宛先(udpSocketSend->writeDatagram(...))を指定し、bind実際に送信データグラムの送信元を決定します。そうでない場合はbind、問題ありません。スタックによってポートが割り当てられます。

送信元ポートを気にする場合、送信元ポートと受信先ポートに異なるポート番号を使用することをお勧めします。そうすれば、送信者と受信者の両方を問題なくバインドできるようになります。

最後に、SO_REUSEADDRソケットオプションを設定するオプションがあります(使用している言語に関係なく)。これは、すべてのクライアントが同じアドレスにバインドする必要があるため、同じマシンで複数のクライアントを実行する場合に必要になります。しかし、このソケットオプションがクロスプラットフォームであるかどうかはわかりません(* nixは正常に機能します)。上記の提案の方が優れていると思います。

于 2012-06-04T20:36:26.320 に答える