2012-06-04 38 views
7

Tôi có một ứng dụng, phần mềm được xác định radio, rằng chương trình phát sóng gói UDP trên một cổng mà nói với người nghe những gì tần số và chế độ giải điều chế đã được thiết lập (trong số những thứ khác.)Python và UDP nghe

Tôi đã viết một bản demo python client (mã bên dưới) lắng nghe cổng, và đưa ra thông tin trong các gói thích hợp với giao diện điều khiển.

Cả hai loại này đều chạy dưới OSX 10.6, Snow Leopard. Họ làm việc ở đó.

Câu hỏi/vấn đề tôi có là: ứng dụng Python phải được bắt đầu trước ứng dụng radio hoặc yêu cầu cổng đã được sử dụng (ERRNO 47) trong quá trình liên kết và tôi không hiểu tại sao. Ứng dụng radio đang phát sóng UDP; chắc chắn tôi muốn thu hút nhiều người nghe - đó là ý tưởng phát sóng, hoặc ít nhất, vì vậy tôi nghĩ.

Vì vậy, đây là mã Python (thụt lề là một chút sai lầm do chồng tràn thực sự câm "make-it-mã" thụt lề, nhưng tôi đảm bảo với bạn nó là ok):

#!/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' 

Để tham khảo, đây là đoạn code Qt đang gửi thông điệp UDP:

Setup:

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

Broadcast:

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 
} 
+0

Hai ứng dụng này đang chạy trên cùng một máy, phải không? – jedwards

+0

Bạn cần phải sửa chữa thụt đầu dòng. Sau 'try:' không thể có một dòng có cùng mức thụt lề như câu lệnh 'try:'. – ThiefMaster

+0

@jedwards, vâng. ThiefMaster: như tôi đã nói ngay trên mã Python, định dạng của stackoverflow đã làm rối loạn thụt lề. Mã được thụt lề một cách chính xác. Không phải lo lắng ở đó. – fyngyrz

Trả lời

6

Bạn đang cố gắng liên kết cùng một cổng, hai lần.

Bạn ràng buộc nó một lần trong sender:

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

và một lần nữa tại máy thu

s.bind(('', port)) 

Và kể từ khi chúng được chạy trên cùng một máy, bạn đang nhận được một lỗi.

Trừ khi bạn quan tâm cổng nguồn là gì, bạn không cần phải bind() trên người gửi, chỉ cần gửi nó và ngăn xếp sẽ chọn một số cổng nguồn đi thích hợp. Trong trường hợp người gửi, khi bạn truyền một gói dữ liệu UDP, bạn chỉ định đích (udpSocketSend->writeDatagram(...)) và bind thực sự xác định nguồn của gói dữ liệu đi. Nếu bạn không bind, điều đó tốt, ngăn xếp sẽ gán cho bạn một cổng.

Nếu bạn làm hãy quan tâm cổng nguồn là gì, khi đó tôi đề nghị bạn sử dụng một số cổng khác cho cổng nguồn đi và cổng đích đến. Sau đó, bạn sẽ có thể ràng buộc cả người gửi và người nhận mà không có vấn đề.

Cuối cùng, có tùy chọn để đặt tùy chọn ổ cắm SO_REUSEADDR (bằng bất kỳ ngôn ngữ nào bạn đang sử dụng). Điều này sẽ là cần thiết nếu bạn muốn chạy nhiều khách hàng trên cùng một máy, vì tất cả khách hàng sẽ phải liên kết với cùng một địa chỉ. Nhưng, tôi không chắc chắn cho dù tùy chọn ổ cắm này là nền tảng chéo (* nix hoạt động tốt) và tôi nghĩ rằng các đề xuất trên là tốt hơn.

+1

+1, nhưng chỉ để làm cho nó hoàn toàn rõ ràng, trong giao tiếp TCP/IP, bạn hầu như không bao giờ quan tâm đến cổng nguồn là gì. Khá nhiều lần duy nhất bạn quan tâm là nếu bạn đang cố gắng thương lượng một bộ quy tắc tường lửa cụ thể. –

+0

Russell: đây là UDP. Không phải TCP. @jedwards: Tôi cần (đơn) ứng dụng để gửi một chương trình phát sóng có thể được nhiều khách hàng nhận. Tôi cần cho khách hàng - có thể một vài trong số họ - để có thể gửi tin nhắn đến ứng dụng. Trong mọi trường hợp, tôi không muốn người dùng thực sự phải thiết lập bất kỳ thứ gì. Dường như ý tưởng phát sóng phù hợp với cả hai đầu (và không có gì khác thực sự dường như.) Tôi có sai không? – fyngyrz

Các vấn đề liên quan