आप पायथन में यूडीपी मल्टीकास्ट कैसे भेजते हैं और प्राप्त करते हैं? क्या ऐसा करने के लिए एक मानक पुस्तकालय है?
जवाबों:
यह मेरे लिए काम करता है:
प्राप्त करना
import socket
import struct
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, 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:
# For Python 3, change next line to "print(sock.recv(10240))"
print sock.recv(10240)
संदेश
import socket
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after two hops on the network the packet will not
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
# For Python 3, change next line to 'sock.sendto(b"robot", ...' to avoid the
# "bytes-like object is required" msg (https://stackoverflow.com/a/42612820)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
यह http://wiki.python.org/moin/UdpCommunication से उन उदाहरणों पर आधारित है जो काम नहीं करते थे।
मेरी प्रणाली है ... लिनक्स 2.6.31-15-जेनेरिक # 50-उबंटू एसएमपी टीयू 10 नवंबर 14:54:29 यूटीसी 2009 i686 जीएनयू / लिनक्स पायथन 2.6.4
sock.bind((MCAST_GRP, MCAST_PORT))
, आपका कोड काम नहीं कर सकता है और नहीं हो सकता है, यह तब काम नहीं कर सकता है जब आपके पास कई
मल्टीकास्ट प्रेषक जो एक मल्टीकास्ट समूह में प्रसारण करता है:
#!/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()
मल्टीकास्ट रिसीवर जो एक मल्टीकास्ट समूह से पढ़ता है और कंसोल पर हेक्स डेटा प्रिंट करता है:
#!/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()
sock.bind((MCAST_GRP, MCAST_PORT))
मल्टीकास्ट समूह में शामिल होने के लिए पायथन देशी ओएस सॉकेट इंटरफ़ेस का उपयोग करता है। पायथन पर्यावरण की पोर्टेबिलिटी और स्थिरता के कारण सॉकेट के कई विकल्प सीधे देशी सॉकेट सेट्सकॉप्ट कॉल पर भेजे जाते हैं। ऑपरेशन की मल्टीकास्ट मोड जैसे कि ग्रुप मेंबरशिप को ज्वाइन करना और ड्रॉप करना जैसे कामों को पूरा किया जा सकता है setsockopt
।
मल्टीकास्ट आईपी पैकेट प्राप्त करने के लिए मूल कार्यक्रम की तरह देख सकते हैं:
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)
सबसे पहले यह सॉकेट बनाता है, इसे बांधता है और ट्रिगर मल्टीकास्ट समूह को जारी करके जुड़ता है setsockopt
। बहुत अंत में यह हमेशा के लिए पैकेट प्राप्त करता है।
मल्टीकास्ट आईपी फ्रेम भेजना सीधे आगे है। यदि आपके पास अपने सिस्टम में सिंगल एनआईसी है तो ऐसे पैकेट भेजना सामान्य यूडीपी फ्रेम भेजने से अलग नहीं है। आपको बस इस बात का ध्यान रखना है कि sendto()
विधि में सही गंतव्य IP पता सेट किया जाए ।
मैंने देखा कि इंटरनेट के आसपास बहुत सारे उदाहरण वास्तव में दुर्घटना से काम करते हैं। यहां तक कि आधिकारिक अजगर प्रलेखन पर भी। उन सभी के लिए समस्या का उपयोग कर रहे हैं struct.pack गलत तरीके से। कृपया सलाह दी जाती है कि विशिष्ट उदाहरण 4sl
प्रारूप के रूप में उपयोग किया जाता है और इसे वास्तविक OS सॉकेट इंटरफ़ेस संरचना के साथ संरेखित नहीं किया जाता है।
मैं वर्णन करने की कोशिश करूंगा कि जब अजगर के सॉकेट ऑब्जेक्ट के लिए सेटसॉकॉप्ट कॉल का उपयोग करते हुए हुड के नीचे क्या होता है।
देशी सी सॉकेट इंटरफ़ेस के लिए पायथन फॉर्वर्ड सेट्सकॉप्ट विधि कॉल। लिनक्स सॉकेट प्रलेखन (देखें man 7 ip
) ip_mreqn
IP_ADD_MEMBERSHIP विकल्प के लिए संरचना के दो रूपों का परिचय देता है। सबसे छोटा फॉर्म 8 बाइट्स लंबा होता है और 12 बाइट्स लंबा होता है। उपरोक्त उदाहरण 8 बाइट setsockopt
कॉल उत्पन्न करता है जहां पहले चार बाइट परिभाषित करते हैं multicast_group
और दूसरे चार बाइट परिभाषित करते हैं interface_ip
।
पाई-मल्टीकास्ट पर एक नजर । नेटवर्क मॉड्यूल यह जांच सकता है कि क्या कोई इंटरफ़ेस मल्टीकास्ट (लिनक्स पर कम से कम) का समर्थन करता है।
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
शायद IGMP को नहीं देखने के साथ समस्याओं, एक इंटरफ़ेस मल्टीकास्ट का समर्थन नहीं करने के कारण थे?
अन्य उत्तरों के कोड में कुछ सूक्ष्म बिंदुओं को समझाने के लिए बस एक और उत्तर:
socket.INADDR_ANY
- (संपादित) के संदर्भ में IP_ADD_MEMBERSHIP
, यह वास्तव में सभी इंटरफेस के लिए सॉकेट को बांधता नहीं है, लेकिन बस डिफ़ॉल्ट इंटरफ़ेस चुनें जहां मल्टीकास्ट ऊपर है (रूटिंग टेबल के अनुसार)देखें कि मल्टीकास्ट (यूडीपी) सॉकेट को बांधने का क्या मतलब है? मल्टीकास्ट कैसे काम करता है, इस पर अधिक जानकारी के लिए
मल्टीकास्ट रिसीवर:
import socket
import struct
import argparse
def run(groups, port, iface=None, bind_group=None):
# generally speaking you want to bind to one of the groups you joined in
# this script,
# but it is also possible to bind to group which is added by some other
# programs (like another python program instance of this)
# assert bind_group in groups + [None], \
# 'bind group not in groups to join'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# allow reuse of socket (to allow another instance of python running this
# script binding to the same ip/port)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('' if bind_group is None else bind_group, port))
for group in groups:
mreq = struct.pack(
'4sl' if iface is None else '4s4s',
socket.inet_aton(group),
socket.INADDR_ANY if iface is None else socket.inet_aton(iface))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print(sock.recv(10240))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--port', type=int, default=19900)
parser.add_argument('--join-mcast-groups', default=[], nargs='*',
help='multicast groups (ip addrs) to listen to join')
parser.add_argument(
'--iface', default=None,
help='local interface to use for listening to multicast data; '
'if unspecified, any interface would be chosen')
parser.add_argument(
'--bind-group', default=None,
help='multicast groups (ip addrs) to bind to for the udp socket; '
'should be one of the multicast groups joined globally '
'(not necessarily joined in this python program) '
'in the interface specified by --iface. '
'If unspecified, bind to 0.0.0.0 '
'(all addresses (all multicast addresses) of that interface)')
args = parser.parse_args()
run(args.join_mcast_groups, args.port, args.iface, args.bind_group)
नमूना उपयोग: (दो कंसोल में नीचे चलाएं और अपना स्वयं का चुनें --iface (मल्टीटास्ट डेटा प्राप्त करने वाले इंटरफ़ेस के समान होना चाहिए))
python3 multicast_recv.py --iface='192.168.56.102' --join-mcast-groups '224.1.1.1' '224.1.1.2' '224.1.1.3' --bind-group '224.1.1.2'
python3 multicast_recv.py --iface='192.168.56.102' --join-mcast-groups '224.1.1.4'
बहुस्तरीय प्रेषक:
import socket
import argparse
def run(group, port):
MULTICAST_TTL = 20
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto(b'from multicast_send.py: ' +
f'group: {group}, port: {port}'.encode(), (group, port))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--mcast-group', default='224.1.1.1')
parser.add_argument('--port', default=19900)
args = parser.parse_args()
run(args.mcast_group, args.port)
नमूना उपयोग: # मान लें कि रिसीवर नीचे मल्टीकास्ट समूह के पते पर बांधता है और यह कि कुछ कार्यक्रम उस समूह में शामिल होने का अनुरोध करते हैं। और मामले को सरल बनाने के लिए, रिसीवर और प्रेषक को एक ही सबनेट के तहत मान लें
python3 multicast_send.py --mcast-group '224.1.1.2'
python3 multicast_send.py --mcast-group '224.1.1.4'
Solaris पर क्लाइंट कोड (tolomea) से काम करने के लिए आपको IP_MULTICAST_TTL
अहस्ताक्षरित चार के रूप में सॉकेट विकल्प के लिए ttl मान को पास करना होगा । अन्यथा आपको एक त्रुटि मिलेगी। इसने मेरे लिए सोलारिस 10 और 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))
टोलोमिया के जवाब ने मेरे लिए काम किया। मैंने इसे सॉकेट्सवर.यूडीपीएसर्वर में भी हैक कर लिया है:
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)