आप यूडीपी मल्टीटास्ट पायथन में कैसे करते हैं?


86

आप पायथन में यूडीपी मल्टीकास्ट कैसे भेजते हैं और प्राप्त करते हैं? क्या ऐसा करने के लिए एक मानक पुस्तकालय है?

जवाबों:


98

यह मेरे लिए काम करता है:

प्राप्त करना

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


6
मैक ओएस एक्स के लिए आपको सॉकेट के लिए एक विकल्प के रूप में सॉकेट का उपयोग करने की आवश्यकता है। एक ही मल्टीकास्ट पोर्ट एड्रेस संयोजन पर कई श्रोताओं को अनुमति देने के लिए उपरोक्त उदाहरण में सॉकेट के लिए। O_REUSEADDR।
एटिकट

भेजने के लिए, मुझे भी "sock.bind ((<स्थानीय IP>, 0))" की आवश्यकता थी, क्योंकि मेरा मल्टीकास्ट श्रोता एक विशेष एडाप्टर से बंधा हुआ था।
मार्क फोरमैन

2
udp मल्टिकास्ट के लिए आपको मल्टीकास्ट समूह से बंधना होगा / पोर्ट नहीं स्थानीय समूह पोर्ट, और sock.bind((MCAST_GRP, MCAST_PORT)), आपका कोड काम नहीं कर सकता है और नहीं हो सकता है, यह तब काम नहीं कर सकता है जब आपके पास कई
nics हैं

@ प्रतिकट: धन्यवाद !! हालाँकि हमें मैक पर इसकी आवश्यकता क्यों है लेकिन उबंटू पर नहीं?
क्युबुबी

2
@RandallCook: जब मैं MCAST_GRP द्वारा '' की जगह लेता हूँ तो मुझे सॉकेट मिलता है। शेर: [इर्रानो 10049] अनुरोधित पता इसके संदर्भ में मान्य नहीं है
stewbasic

17

मल्टीकास्ट प्रेषक जो एक मल्टीकास्ट समूह में प्रसारण करता है:

#!/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()

मैंने यह कोशिश की, यह काम नहीं किया। विंडसरक में मैं संचारित देख सकता हूं, लेकिन मैं किसी भी IGMP को सामान में शामिल नहीं देखता हूं और मुझे कुछ भी प्राप्त नहीं होता है।
गॉर्डन Wrigley

1
आपको मल्टीकास्ट ग्रुप पर मल्टीकास्ट ग्रुप / पोर्ट sock.bind((MCAST_GRP, MCAST_PORT))
नॉट

1
यह उदाहरण मेरे लिए काम नहीं करता है, एक अस्पष्ट कारण के लिए। इंटरफ़ेस का चयन करने के लिए socket.gethostbyname (socket.gethostname ()) का उपयोग करना हमेशा बाहरी इंटरफ़ेस का चुनाव नहीं करता है - वास्तव में, डेबियन सिस्टम पर, यह लूपबैक पते का चयन करता है। Debian होस्टनाम के लिए होस्ट तालिका में 127.0.1.1 की प्रविष्टि जोड़ता है। इसके बजाय, सॉकेट का उपयोग करना अधिक प्रभावी है ।INADDR_ANY, जो उच्च रैंकिंग उत्तर 'पैक' स्टेटमेंट (जो '+' की तुलना में अधिक सही है) के माध्यम से उपयोग करता है। इसके अलावा, IP_MULTICAST_IF के उपयोग की आवश्यकता नहीं है, क्योंकि उच्च रैंकिंग उत्तर सही ढंग से बताता है।
ब्रायन बुलकोवस्की

1
@BrianBulkowski ऐसे कई प्रोग्रामर हैं जो सॉकेट का उपयोग करते हैं ।INADDR_ANY, कई इंटरफेस के साथ हम में से बहुत से लोगों के लिए बहुत परेशानी है, जिसे किसी विशेष इंटरफ़ेस पर आने के लिए मल्टीकास्ट डेटा की आवश्यकता होती है। समाधान सॉकेट नहीं है ।INADDR_ANY। यह आईपी पते द्वारा उचित इंटरफ़ेस का चयन करना है, हालांकि आपको लगता है कि सबसे अच्छा है (एक कॉन्फ़िगर फ़ाइल, अंत उपयोगकर्ता से पूछ रहा है, हालांकि आप अपने आवेदन की जरूरतों के लिए चुनते हैं)। socket.INADDR_ANY आपको मल्टीकास्ट डेटा मिलेगा, यह सच है, और आसान है यदि आप एकल-होम होस्ट करते हैं, लेकिन मुझे लगता है कि यह कम सही है।
माइक एस।

@ माइक जब मैं किसी सिद्धांत में आपसे सहमत हूं, तो इंटरफेस चुनने के लिए आईपी पते का उपयोग करने का विचार बहुत बुरा है, बहुत ही भयावह है। मुझे समस्या अच्छी तरह से पता है, लेकिन एक गतिशील दुनिया में, और आईपी पते का जवाब नहीं है। तो आपको कोड लिखने की ज़रूरत है जो इंटरफ़ेस नाम से सब कुछ और चुनता है, इंटरफ़ेस नाम को देखता है, वर्तमान आईपी पते को चुनता है, और इसका उपयोग करता है। उम्मीद है, इस बीच आईपी पता नहीं बदला है। मैं चाहता हूं कि लिनक्स / यूनिक्स ने हर जगह इंटरफ़ेस नामों का उपयोग करने पर मानकीकरण किया था, और प्रोग्रामिंग भाषाओं में था, जो एक कॉन्फ़िगर फ़ाइल को अधिक समझदार बना देगा।
ब्रायन बुल्कोव्स्की

13

बेहतर उपयोग:

sock.bind((MCAST_GRP, MCAST_PORT))

के बजाय:

sock.bind(('', MCAST_PORT))

क्योंकि, यदि आप एक ही पोर्ट पर कई मल्टीकास्ट समूहों को सुनना चाहते हैं, तो आपको सभी श्रोताओं पर सभी संदेश मिलेंगे।


6

मल्टीकास्ट समूह में शामिल होने के लिए पायथन देशी ओएस सॉकेट इंटरफ़ेस का उपयोग करता है। पायथन पर्यावरण की पोर्टेबिलिटी और स्थिरता के कारण सॉकेट के कई विकल्प सीधे देशी सॉकेट सेट्सकॉप्ट कॉल पर भेजे जाते हैं। ऑपरेशन की मल्टीकास्ट मोड जैसे कि ग्रुप मेंबरशिप को ज्वाइन करना और ड्रॉप करना जैसे कामों को पूरा किया जा सकता है 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_mreqnIP_ADD_MEMBERSHIP विकल्प के लिए संरचना के दो रूपों का परिचय देता है। सबसे छोटा फॉर्म 8 बाइट्स लंबा होता है और 12 बाइट्स लंबा होता है। उपरोक्त उदाहरण 8 बाइट setsockoptकॉल उत्पन्न करता है जहां पहले चार बाइट परिभाषित करते हैं multicast_groupऔर दूसरे चार बाइट परिभाषित करते हैं interface_ip


2

पाई-मल्टीकास्ट पर एक नजर । नेटवर्क मॉड्यूल यह जांच सकता है कि क्या कोई इंटरफ़ेस मल्टीकास्ट (लिनक्स पर कम से कम) का समर्थन करता है।

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 को नहीं देखने के साथ समस्याओं, एक इंटरफ़ेस मल्टीकास्ट का समर्थन नहीं करने के कारण थे?


2

अन्य उत्तरों के कोड में कुछ सूक्ष्म बिंदुओं को समझाने के लिए बस एक और उत्तर:

  • 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'


INADDR_ANY 'स्थानीय इंटरफेस में से एक का चयन नहीं करता है]'।
लोरेन

0

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))

-1

टोलोमिया के जवाब ने मेरे लिए काम किया। मैंने इसे सॉकेट्सवर.यूडीपीएसर्वर में भी हैक कर लिया है:

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.