Làm thế nào để bạn gửi và nhận Multicast UDP bằng Python? Có thư viện chuẩn để làm như vậy không?Multicast bằng Python
Trả lời
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.
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()
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ả. –
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
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. –
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
Đố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
Để gửi, tôi cũng cần "sock.bind ((
để 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
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
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
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)
Có một khuôn khổ để làm điều này từ http://twistedmatrix.com/trac/. Dưới đây là ví dụ https://twistedmatrix.com/documents/12.2.0/core/howto/udp.html
Để 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))
Một ví dụ điển hình mà làm việc cho tôi:
http://svn.python.org/projects/stackless/trunk/Demo/sockets/mcast.py
Để 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
.
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ể. –
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. –