2009-03-02 25 views

Trả lời

-1

Lưu lượng truy cập đa phương tiện không khác với UDP thông thường trừ địa chỉ IP. Hãy xem tiêu chuẩn socket library. Bạn có thể tìm thấy thứ gì đó được xây dựng trên ổ cắm và dễ sử dụng hơn.

+0

Phải. Nhưng làm thế nào về việc gia nhập một nhóm? Tôi không muốn quản lý nhóm của riêng mình nếu có thể. –

+7

Lưu lượng truy cập đa phương tiện là _quite_ khác với lưu lượng UDP thông thường (unicast): Bạn cần tham gia nhóm multicast, tất cả các thiết bị chuyển mạch và bộ định tuyến cần phải xử lý các tác động, vấn đề TTL, thường không được định tuyến qua WAN. –

16

Multicast người gửi rằng chương trình phát sóng cho một nhóm multicast:

#!/usr/bin/env python 

import socket 
import struct 

def main(): 
    MCAST_GRP = '224.1.1.1' 
    MCAST_PORT = 5007 
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) 
    sock.sendto('Hello World!', (MCAST_GRP, MCAST_PORT)) 

if __name__ == '__main__': 
    main() 

Multicast nhận mà đọc từ một nhóm multicast và in dữ liệu hex ra cửa sổ Console:

#!/usr/bin/env python 

import socket 
import binascii 

def main(): 
    MCAST_GRP = '224.1.1.1' 
    MCAST_PORT = 5007 
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
    try: 
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    except AttributeError: 
    pass 
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 32) 
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1) 

    sock.bind((MCAST_GRP, MCAST_PORT)) 
    host = socket.gethostbyname(socket.gethostname()) 
    sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(host)) 
    sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, 
        socket.inet_aton(MCAST_GRP) + socket.inet_aton(host)) 

    while 1: 
    try: 
     data, addr = sock.recvfrom(1024) 
    except socket.error, e: 
     print 'Expection' 
     hexdata = binascii.hexlify(data) 
     print 'Data = %s' % hexdata 

if __name__ == '__main__': 
    main() 
+0

Tôi đã thử điều này, nó không hoạt động. Trong Wireshark tôi có thể thấy sự truyền tải, nhưng tôi không thấy bất kỳ thứ gì tham gia vào IGMP và tôi không nhận được gì cả. –

+1

bạn cần liên kết với nhóm/cổng multicast không phải cổng cục bộ trên địa chỉ multicast, 'sock.bind ((MCAST_GRP, MCAST_PORT))' – stefanB

+0

Ví dụ này không hoạt động đối với tôi, vì một lý do không rõ ràng. Sử dụng socket.gethostbyname (socket.gethostname()) để chọn giao diện không phải lúc nào cũng chọn giao diện bên ngoài - trên thực tế, trên các hệ thống debian, nó có xu hướng chọn địa chỉ loopback. Debian thêm một mục 127.0.1.1 vào bảng chủ cho tên máy chủ. Thay vào đó, sử dụng socket.INADDR_ANY hiệu quả hơn, câu trả lời xếp hạng cao hơn sử dụng thông qua câu lệnh 'gói' (chính xác hơn '+'). Ngoài ra, việc sử dụng IP_MULTICAST_IF là không bắt buộc, vì câu trả lời xếp hạng cao hơn sẽ chính xác hơn. –

78

này làm việc cho tôi:

Nhận

import socket 
import struct 

MCAST_GRP = '224.1.1.1' 
MCAST_PORT = 5007 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
sock.bind(('', MCAST_PORT)) # use MCAST_GRP instead of '' to listen only 
          # to MCAST_GRP, not all groups on MCAST_PORT 
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) 

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 

while True: 
    print sock.recv(10240) 

Gửi

import socket 

MCAST_GRP = '224.1.1.1' 
MCAST_PORT = 5007 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) 
sock.sendto("robot", (MCAST_GRP, MCAST_PORT)) 

Nó được dựa trên các ví dụ từ http://wiki.python.org/moin/UdpCommunication mà không làm việc.

hệ thống của tôi là ... Linux 2.6.31-15-generiC# 50-Ubuntu SMP Tue 10 tháng 11 14:54:29 UTC 2009 i686 GNU/Linux Python 2.6.4

+6

Đối với mac os x bạn cần sử dụng tùy chọn socket.SO_REUSEPORT làm phương án thay thế cho socket.SO_REUSEADDR trong ví dụ trên, cho phép nhiều người nghe trên cùng một kết hợp địa chỉ cổng multicast. – atikat

+0

Để gửi, tôi cũng cần "sock.bind ((, 0))" vì trình nghe multicast của tôi bị ràng buộc với một bộ điều hợp cụ thể. –

+2

để phát đa hướng udp, bạn cần phải liên kết với nhóm/cổng multicast không phải cổng nhóm cục bộ, 'sock.bind ((MCAST_GRP, MCAST_PORT))', mã của bạn có thể và có thể không hoạt động, nó có thể không hoạt động khi bạn có nhiều nics – stefanB

2

Có một cái nhìn tại py-multicast. Mô-đun mạng có thể kiểm tra xem một giao diện có hỗ trợ phát đa hướng (ít nhất là trên Linux) hay không.

import multicast 
from multicast import network 

receiver = multicast.MulticastUDPReceiver ("eth0", "238.0.0.1", 1234) 
data = receiver.read() 
receiver.close() 

config = network.ifconfig() 
print config['eth0'].addresses 
# ['10.0.0.1'] 
print config['eth0'].multicast 
#True - eth0 supports multicast 
print config['eth0'].up 
#True - eth0 is up 

Có thể vấn đề không nhìn thấy IGMP là do giao diện không hỗ trợ phát đa hướng? sử dụng

+0

http://coobs.eu.org/py-multicast/ liên kết bị hỏng – balki

+2

vì vậy nó là :(, bây giờ bạn có thể thử điều này: http://pypi.python.org/pypi/py-multicast – wroniasty

8

tốt hơn:

sock.bind((MCAST_GRP, MCAST_PORT)) 

thay vì:

sock.bind(('', MCAST_PORT)) 

... bởi vì nếu bạn muốn nghe nhiều nhóm mcast trên cổng cùng, bạn sẽ nhận được tất cả các tin nhắn trong tất cả người nghe

0

câu trả lời của tolomea có hiệu quả đối với tôi. Tôi đã hack nó vào socketserver.UDPServer quá:

class ThreadedMulticastServer(socketserver.ThreadingMixIn, socketserver.UDPServer): 
    def __init__(self, *args): 
     super().__init__(*args) 
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     self.socket.bind((MCAST_GRP, MCAST_PORT)) 
     mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY) 
     self.socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 
0

Để làm cho mã khách hàng (từ tolomea) hoạt động trên Solaris, bạn cần phải chuyển giá trị ttl cho tùy chọn ổ cắm IP_MULTICAST_TTL làm dấu chưa ký. Nếu không, bạn sẽ gặp lỗi. này làm việc cho tôi trên Solaris 10 và 11:

import socket 
import struct 

MCAST_GRP = '224.1.1.1' 
MCAST_PORT = 5007 
ttl = struct.pack('B', 2) 

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl) 
sock.sendto("robot", (MCAST_GRP, MCAST_PORT)) 
1

Để Tham gia nhóm multicast Python sử dụng giao diện ổ cắm hệ điều hành bản địa.Do tính di động và tính ổn định của môi trường Python, nhiều tùy chọn socket được chuyển tiếp trực tiếp đến lệnh gọi socket setockopt. Chế độ hoạt động đa hướng như tham gia và bỏ tư cách thành viên nhóm chỉ có thể được thực hiện bởi chỉ setsockopt.

chương trình cơ bản để tiếp nhận gói tin IP multicast có thể trông giống như:

from socket import * 

multicast_port = 55555 
multicast_group = "224.1.1.1" 
interface_ip = "10.11.1.43" 

s = socket(AF_INET, SOCK_DGRAM) 
s.bind(("", multicast_port)) 
mreq = inet_aton(multicast_group) + inet_aton(interface_ip) 
s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, str(mreq)) 

while 1: 
    print s.recv(1500) 

Thứ nhất nó tạo socket, liên kết với nó và gây nên gây nên nhóm multicast tham gia bằng cách phát hành setsockopt. Cuối cùng nó nhận được các gói tin mãi mãi.

Gửi khung IP đa hướng thẳng về phía trước. Nếu bạn có một NIC duy nhất trong hệ thống của bạn gửi các gói như vậy không khác với các khung UDP thông thường gửi đi. Tất cả những gì bạn cần phải quan tâm là chỉ cần đặt địa chỉ IP đích chính xác theo phương thức sendto().

Tôi nhận thấy rằng rất nhiều ví dụ về các tác phẩm Internet do tai nạn trên thực tế. Ngay cả trên tài liệu python chính thức. Vấn đề cho tất cả chúng đang sử dụng struct.pack không chính xác. Xin lưu ý rằng ví dụ điển hình sử dụng định dạng 4sl và định dạng này không phù hợp với cấu trúc giao diện socket OS thực tế.

Tôi sẽ cố gắng mô tả những gì xảy ra bên dưới mui xe khi thực hiện lệnh setockopt cho đối tượng socket python.

Python chuyển tiếp phương thức setockopt gọi đến giao diện ổ cắm C gốc. Tài liệu về socket Linux (xem man 7 ip) giới thiệu hai dạng của ip_mreqn cấu trúc cho tùy chọn IP_ADD_MEMBERSHIP. Ngắn nhất là dạng dài 8 byte và dài hơn 12 byte. Ví dụ trên tạo ra 8 byte setsockopt gọi nơi nắm tay cho các byte xác định multicast_group và thứ hai interface_ip.