Python에서 UDP 멀티 캐스트는 어떻게합니까?
Python에서 UDP 멀티 캐스트를 어떻게 보내고 받습니까? 그렇게 할 수있는 표준 라이브러리가 있습니까?
이것은 나를 위해 작동합니다.
받다
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:
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)
sock.sendto("robot", (MCAST_GRP, MCAST_PORT))
작동하지 않는 http://wiki.python.org/moin/UdpCommunication 의 예제를 기반으로 합니다.
내 시스템은 ... Linux 2.6.31-15-generic # 50-Ubuntu SMP Tue Nov 10 14:54:29 UTC 2009 i686 GNU / Linux Python 2.6.4
멀티 캐스트 그룹에 브로드 캐스트하는 멀티 캐스트 발신자 :
#!/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()
멀티 캐스트 그룹에서 읽고 16 진 데이터를 콘솔에 인쇄하는 멀티 캐스트 수신기 :
#!/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))
대신에:
sock.bind(('', MCAST_PORT))
같은 포트에서 여러 멀티 캐스트 그룹을 수신하려면 모든 리스너에서 모든 메시지를 받게됩니다.
멀티 캐스트 그룹에 참여하기 위해 Python은 기본 OS 소켓 인터페이스를 사용합니다. Python 환경의 이식성과 안정성으로 인해 많은 소켓 옵션이 네이티브 소켓 setsockopt 호출로 직접 전달됩니다. 그룹 멤버십 가입 및 탈퇴와 같은 멀티 캐스트 작동 모드는에 setsockopt
의해서만 수행 될 수 있습니다 .
멀티 캐스트 IP 패킷 수신을위한 기본 프로그램은 다음과 같습니다.
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
. 마지막에는 패킷을 영원히받습니다.
멀티 캐스트 IP 프레임 전송은 간단합니다. 시스템에 단일 NIC가있는 경우 이러한 패킷을 보내는 것은 일반적인 UDP 프레임 전송과 다르지 않습니다. 주의해야 할 것은 sendto()
방법에 올바른 대상 IP 주소를 설정하는 것뿐입니다 .
사실 인터넷에 대한 많은 예가 우연히 작동한다는 것을 알았습니다. 공식 파이썬 문서에서도. 그들 모두에 대한 문제는 struct.pack을 잘못 사용하고 있습니다. 일반적인 예제는 4sl
형식으로 사용 되며 실제 OS 소켓 인터페이스 구조와 일치하지 않습니다.
파이썬 소켓 객체에 대한 setsockopt 호출을 실행할 때 후드 아래에서 일어나는 일을 설명하려고 노력할 것입니다.
Python은 setsockopt 메서드 호출을 네이티브 C 소켓 인터페이스로 전달합니다. Linux 소켓 설명서 (참조 man 7 ip
)에서는 ip_mreqn
IP_ADD_MEMBERSHIP 옵션에 대한 두 가지 형태의 구조를 소개 합니다. 가장 짧은 형식은 8 바이트 길이이고 더 긴 형식은 12 바이트입니다. 위의 예는 setsockopt
fist for bytes가 정의 multicast_group
하고 second를 정의 하는 8 바이트 호출을 생성 합니다 interface_ip
.
py-multicast를 살펴보십시오 . 네트워크 모듈은 인터페이스가 멀티 캐스트를 지원하는지 확인할 수 있습니다 (최소한 Linux에서).
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
에서 이것은 실제로 소켓을 모든 인터페이스에 바인딩하지 않고 멀티 캐스트가 작동하는 기본 인터페이스를 선택합니다 (라우팅 테이블에 따라).- 멀티 캐스트 그룹에 참여하는 것은 소켓을 로컬 인터페이스 주소에 바인딩하는 것과 다릅니다.
멀티 캐스트 (UDP) 소켓을 바인드한다는 것은 무엇을 의미합니까?를 참조하십시오 . 멀티 캐스트 작동 방식에 대한 자세한 내용
멀티 캐스트 수신기 :
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)
sample usage: (run the below in two consoles and choose your own --iface (must be same as the interface that receives the multicast data))
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'
Multicast sender:
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)
sample usage: # assume the receiver binds to the below multicast group address and that some program requests to join that group. And to simplify the case, assume the receiver and the sender are under the same subnet
python3 multicast_send.py --mcast-group '224.1.1.2'
python3 multicast_send.py --mcast-group '224.1.1.4'
To make the client code (from tolomea) work on Solaris you need to pass the ttl value for the IP_MULTICAST_TTL
socket option as an unsigned char. Otherwise you will get an error. This worked for me on Solaris 10 and 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))
tolomea's answer worked for me. I hacked it into socketserver.UDPServer too:
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)
참고URL : https://stackoverflow.com/questions/603852/how-do-you-udp-multicast-in-python
'Program Tip' 카테고리의 다른 글
진행률 표시 줄의 숫자는 Spark-shell에서 무엇을 의미합니까? (0) | 2020.10.05 |
---|---|
코드를 작성하기 전에 애플리케이션의 아키텍처를 어떻게 계획합니까? (0) | 2020.10.05 |
모든 가상 함수를 파생 클래스에서 구현해야합니까? (0) | 2020.10.05 |
URL이 작동 중일 때 "java.net.ConnectException : Connection timed out"예외가 발생하는 이유는 무엇입니까? (0) | 2020.10.05 |
css 'ex'단위의 가치는 무엇입니까? (0) | 2020.10.05 |