지금까지 나는 멀티캐스트에 ipv4를 사용하고 있으며 관련된 모든 컴퓨터는 Linux를 실행합니다. 나는 두 대의 컴퓨터에서 듣고 그 중 하나(별도의 터미널)로 보냅니다. 다음 예에서는 보내는 컴퓨터(strawberry)와 원격 컴퓨터(ero)에서 "Hello 1"을 수신합니다.
ero:~$ sudo ip addr add 224.4.19.42 dev enp4s0 autojoin
ero:~$ netcat -l -k -u -p 9988
strawberry:~ $ sudo ip addr add 224.4.19.42 dev wlan0 autojoin
strawberry:~ $ netcat -l -k -u -p 9988
strawberry:~ $ echo "Hello 1" | netcat -s 192.168.178.109 -w 0 -u 224.4.19.42 9988
ipv6을 사용하면 원격 시스템만 수신하는 한 작동합니다. 아래 예에서는 "Hello 2"가 ero에 의해 수신됩니다. 발신자(strawberry)도 멀티캐스트 그룹에 참여하면 발신자(strawberry)나 원격 시스템(ero) 모두 "Hello 3"을 수신하지 않습니다.
ero:~$ sudo ip addr add ff05:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:4141 dev enp4s0 autojoin
ero:~$ netcat -l -k -u -p 9988
strawberry:~ $ echo "Hello 2" | netcat -w 0 -s 2001:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:76d0 -u ff05:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:4141 9988
strawberry:~ $ sudo ip addr add ff05:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:4141 dev wlan0 autojoin
strawberry:~ $ netcat -l -k -u -p 9988
strawberry:~ $ echo "Hello 3" | netcat -w 0 -s 2001:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:76d0 -u ff05:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:4141 9988
어쩌면 흥미로울 수도 있습니다. 발신자 주소를 제공하지 않으면, 즉 -s 옵션이 없으면 ipv4 예제는 ipv6과 동일한 동작을 보여줍니다. 딸기가 멀티캐스트 그룹에 가입되지 않은 경우에만 메시지가 수신됩니다. 그래서 ipv6을 사용하여 다른 전송 주소를 시도했습니다: 예제에 표시된 전역 주소(2001:...), 고유 로컬 주소(ULA; fd00:...) 및 링크 로컬 주소(LLA; fe80:.. .) .) . 둘 다 도움이 되지 않습니다.
내가 뭘 잘못하고 있는지에 대한 힌트가 있습니까?
답변1
소개하다
호스트 시스템의 경우 멀티캐스트 IP 주소로 보내는 것은 유니캐스트 주소로 보내는 것과 매우 유사하지만 멀티캐스트를 받는 것은 다르며 추가 API를 사용합니다. 호스트는 멀티캐스트 주소를 인터페이스에 할당하지 않고 대신 애플리케이션이 연결될 때 이를 조인합니다. 요청 시(소켓 사용) 선택된 멀티캐스트 트래픽을 수신하는 데 관심이 있는 프로그램입니다. 이것은RFC 1112에 설명되어 있음. RFC호스트 그룹에 가입그리고호스트 그룹 탈퇴이 함수는 다음을 사용하여 대부분의 *nix에서 사용되는 BSD 소켓 API로 전환됩니다.setsockopt(2)
멀티캐스트 그룹에 가입하고 탈퇴하는 옵션입니다. IPv6은 IPv4와 동일하게 따르지만 라우팅 동작을 포함하여 차이점이 있습니다. POSIX는 짝수입니다.희귀한 장소IPv6 API를 구현하는 방법(IPv4에 대한 멀티캐스트를 너무 많이 설명하지 않는 것 같습니다. 아마도 운영 체제 간에 더 단편화되어 있어서 가치가 없기 때문일 것입니다).
Linux에서 사용되는 기본 소켓 옵션은 다음과 같습니다.IP_MULTICAST_IF
추가하다IP_ADD_MEMBERSHIP
IPv4 및IPV6_MULTICAST_IF
추가하다IPV6_ADD_MEMBERSHIP
(POSIX 호환 별칭 IPV6_JOIN_GROUP
)(IPv6용). OP의 질문도 흥미롭지만 기본적으로 활성화되어 있습니다.IP_MULTICAST_LOOP
그리고IPV6_MULTICAST_LOOP
.
회선에서 무슨 일이 일어나고 있는지 이해하여 네트워크에서 작동하도록 합니다(멀티캐스트 그룹 관리 프로토콜IPv4의 경우 또는MLDIPv6의 경우...) 또는 네트워크 전반에 걸쳐(예:PIM-SM)은 애플리케이션 수준에서는 필요하지 않습니다(그러나 특히 스위치 및 멀티캐스트 청취와 관련된 문제를 해결하는 데 필요할 수 있음).
나머지 대답은 시스템의 네트워크 구성에 대한 특별한 수정이 없을 것으로 예상합니다. 인터페이스에 멀티캐스트 주소가 추가되지 않으며 옵션도 없습니다 autojoin
. 또한 224.4.19.42는 다음에 속합니다.런던 증권 거래소에 할당된 AD-HOC 블록 II 블록. 사적인로컬 범위 블록 구성선택 할수있다239.0.0.0/8 이내.
인터넷 고양이
인터넷 고양이(모두 그변형)는 멀티캐스트를 처리하지 않습니다. 따라서 네트워크 설정을 조정하여 (자동으로 참여일반적으로 터널과 관련된 구성과 함께 사용하도록 의도됨) OP는 IPv4 멀티캐스트 주소와 함께 netcat을 사용하도록 관리되었지만 IPv6에서는 그렇지 않았습니다. 실제로 멀티캐스트를 사용하는 모든 응용 프로그램은 표준을 따르고 추가 API를 사용하여 적절한 멀티캐스트 브로드캐스트 지원을 얻습니다. . 다음과 같은 진단 도구인터넷 고양이더 복잡한 소프트웨어를 교체하는 데 사용되지만 이 교체는 동일한 작업을 수행할 수 있어야 합니다.인터넷 고양이에 익숙해.
소캇
IPv4
소캇이미 (거의) 완료되었습니다IPv4 멀티캐스트 지원.
그러한 멀티캐스트 그룹에 전송하는 방법은 어떤 멀티캐스트 지원 인터페이스를 통해 전송되어야 하는지를 지정하는 것입니다(실제로는소캇이 API는 주소 변형만 지원하는 것으로 보여 사용시 인터페이스를 제공할 수 없습니다.소캇API가 지원하지만 사용하지 않는 한다란원래 setsockopt
socat 옵션, 아래 참조), 선택적으로 멀티캐스트 루프백이 필요한지 여부를 선언합니다(기본적으로 활성화되어 있으므로 여기서는 사용하지 않으므로 예제에 넣겠습니다).
Strawberry에서는 기본 경로가 있거나 적어도 멀티캐스트 224.4.19.42에 대한 예상 인터페이스를 사용하는 경로가 있으면 충분합니다(첫 번째 명령에는 멀티캐스트 관련 기능이 필요하지 않으므로 nc
사용할 수 있는 유일한 경우입니다). :
echo "Hello 1" | socat -u - UDP4-DATAGRAM:224.4.19.42:9988
echo "Hello 1" | socat -u - UDP4-DATAGRAM:224.4.19.42:9988,ip-multicast-loop=1
그렇지 않으면 인터페이스의 주소로 인터페이스를 지정해야 합니다.
echo "Hello 1" | socat -u - UDP4-DATAGRAM:224.4.19.42:9988,ip-multicast-if=192.168.178.109
기록된 사용다란형식 1은 지원되지 않는 소개 단락에 설명된 API 부분에 대한 옵션을 socat
사용 하여 임의의 소켓 옵션을 사용할 수 있습니다 . setsockopt
이는 운영 체제이며 아키텍처에 따라 달라질 수 있습니다. amd64(x86_64) 아키텍처의 Linux(>= 3.5)가 여기에 소개됩니다.
SOL_IP
= 0
IP_MULTICAST_IF
= 32
in_mreq
API 변형에 대해 예상되는 대체 구조: IPv4 멀티캐스트 주소(프리앰블에 의해 도입된 빅엔디안 형식 IPv4 주소의 16진수 4바이트 x
)와 로컬 주소(또 다른 4바이트). 변형 의 in_mreqn
경우: 선행 i
. 모든 매개변수가 필요한 것은 아닙니다. 작업 예제(JSON 형식 사용 및jq
인터페이스 인덱스 계산 명령 wlan0
):
echo "Hello 1" | socat -u - UDP4-DATAGRAM:224.4.19.42:9988,setsockopt=0:32:x00000000xc0a8b26d
echo "Hello 1" | socat -u - UDP4-DATAGRAM:224.4.19.42:9988,setsockopt=0:32:x00000000x00000000i$(ip -j link show enp4s0 | jq '.[].ifindex')
사용하는 경우 ip-multicast-loop=0
Strawberry는 자체적으로 방출되는 멀티캐스트 트래픽을 수신하지 않습니다.
수신 부분은 IP_ADD_MEMBERSHIP
참여할 멀티캐스트 IP 주소 그룹을 지정하는 데 사용해야 하며, 로컬 주소나 인터페이스를 선택할 수도 있습니다(올바른 주소를 선택하기 위해 라우팅 스택에 의존하지 않으려는 경우 이러한 옵션 중 하나가 다시 필요함). 선택) 멀티캐스트로 이동하지 않고 주소에 대한 올바른 경로(예: 기본 경로가 없거나 기본 경로가 잘못된 경우). 소켓이 다른 주소에 바인딩된 경우에도 이 로컬 주소를 선언할 필요가 없습니다. 그렇지 않으면 INADDR_ANY
운영 체제가 이 선택을 따릅니다. 수신 부분은 일반적으로 UDP4-RECV
(수신 병합) 또는 UDP4-RECVFROM
(각 데이터그램 분할) 옵션을 사용할 수 있습니다 fork
. 예를 들어:
224.4.19.42(기본값 포함)에 대한 경로가 있는 경우 두 호스트 모두에서 다음을 수행합니다.
socat -u UDP4-RECV:9988,ip-add-membership=224.4.19.42:0.0.0.0 -
그렇지 않은 경우(여기서 인터페이스 이름 구문 선택)
~을 위한딸기:
socat -u UDP4-RECV:9988,ip-add-membership=224.4.19.42:wlan0 -
~을 위한가아라:
socat -u UDP4-RECV:9988,ip-add-membership=224.4.19.42:enp4s0 -
IPv6
IPv6 지원은 부분적으로 구현된 것 같습니다. ip-add-membership
IPv4와 유사하게 동등한 옵션이 ipv6-add-membership
소스 코드에 존재하고 작동하지만 어디에도 문서화되어 있지 않습니다. 모든 테스트에 사용되는소카트 7.4.1그러니 이 버전을 보여주세요. 이것옵션이 존재합니다:
#ifdef IPV6_JOIN_GROUP
IF_IP6 ("ipv6-add-membership", &opt_ipv6_join_group)
#endif
또는 별칭:
#ifdef IPV6_JOIN_GROUP
IF_IP6 ("ipv6-join-group", &opt_ipv6_join_group)
#endif
그리고형식문나중에 사용 하려면 setsockopt(2)
:
#ifdef IPV6_JOIN_GROUP
const struct optdesc opt_ipv6_join_group = { "ipv6-join-group", "join-group", OPT_IPV6_JOIN_GROUP, GROUP_SOCK_IP6, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IPV6, IPV6_JOIN_GROUP };
#endif
따라서 실제로 기본 멀티캐스트 IPv6 청취가 지원됩니다(그렇지 않으면 dalan이 필요함).setsockopt-listen
소캇최신 버전의 옵션이 필요합니다). 옵션이 없기 때문에 ipv6-multicast-if
(아직?) 기본 라우팅 스택을 사용하여 전송을 거부하는 것은 불가능합니다. dalan 형식은 계속 사용할 수 있습니다. 사용된 구조에는 IPV6_MULTICAST_IF
인터페이스 인덱스만 필요합니다. IPV6_MULTICAST_IF
IPv6 멀티캐스트 범위가 사이트-로컬 범위보다 낮은 경우(예: ff01::/16 또는 ff02::/16) 항상 필요할 수 있지만 다른 경우에는 종종 필요할 수 있습니다(아래 참조). 다시 말하지만, 이 매개변수는 ipv6-multicast-loop
아직 구현되지 않았으므로 dalan 형식의 setockopt 옵션도 필요합니다.
여기서 IPv6 라우팅 동작은 IPv4와 약간 다릅니다. 기본 경로를 따르지 않을 수 있으며 인터페이스가 (재)구성되는 순서에 따라 명시적으로 정의된 경로 없이 여러 인터페이스를 사용하는 시스템에서 정의되지 않은 동작이 있을 수 있습니다. 라우팅 테이블은 다음에서 전환할 수 있습니다.
# ip -6 route show table all type multicast
multicast ff00::/8 dev wlan0 table local proto kernel metric 256 pref medium
multicast ff00::/8 dev dummy0 table local proto kernel metric 256 pref medium
도착하다
# ip -6 route show table all type multicast
multicast ff00::/8 dev dummy0 table local proto kernel metric 256 pref medium
multicast ff00::/8 dev wlan0 table local proto kernel metric 256 pref medium
인터페이스가 다운되었다가 다시 올라온다고 해서 사용할 기본 인터페이스를 변경하는 것입니다. 모든 유형의 컨테이너, 가상 머신 또는 동적 인터페이스를 실행하면 이 문제가 발생할 수 있습니다.
마지막으로 시스템의 라우팅 스택 선택을 신뢰하여 맹목적으로 보냅니다(또는 라우팅이 올바르게 구성된 것으로 알려진 경우).딸기(IPv6에서 요구하는 쉘 해석 대괄호를 피하기 위해 따옴표를 참고하세요):
echo "Hello 1" | socat -u - UDP6-DATAGRAM:'[ff05::4141]':9988
멀티캐스트 루프백을 사용하려면 dalan 형식 옵션이 필요함을 명시적으로 지정하고 보낼 인터페이스를 지정합니다 setsockopt
.
SOL_IPV6
= 41
IPV6_MULTICAST_LOOP
= 19
IPV6_MULTICAST_IF
= 17 부울: 실제로
IPV6_MULTICAST_LOOP
정수의 인덱스(따라서 dalan 데이터 형식에 사용되는 문자): 정수i
IPV6_MULTICAST_IF
echo "Hello 1" | socat -u - UDP6-DATAGRAM:'[ff05::4141]':9988,setsockopt=41:19:i1,setsockopt=41:17:i$(ip -j link show wlan0 | jq '.[].ifindex')
에 수신됨딸기:
socat -u UDP6-RECV:9988,ipv6-add-membership='[ff05::4141]':wlan0 -
또한 받았다가아라:
socat -u UDP6-RECV:9988,ipv6-add-membership='[ff05::4141]':enp4s0 -
피어 수에 관계없이 IPv6 멀티캐스트 통신이 가능합니다. 다음은 자체 루프백 멀티캐스트 트래픽 수신을 비활성화하고 인터페이스를 지정하는 예입니다.
딸기:
socat UDP6-DATAGRAM:'[ff05::4141]':9988,bind=:9988,ipv6-add-membership='[ff05::4141]':wlan0,setsockopt=41:19:i0,setsockopt=41:17:i$(ip -j link show wlan0 | jq '.[].ifindex') -
가아라(동일합니다. 인터페이스 이름에만 기회가 있습니다):
socat UDP6-DATAGRAM:'[ff05::4141]':9988,bind=:9988,ipv6-add-membership='[ff05::4141]':enp4s0,setsockopt=41:19:i0,setsockopt=41:17:i$(ip -j link show enp4s0 | jq '.[].ifindex') -
다른 시스템에서도 동일한 명령을 실행할 수 있지만 인터페이스 이름은 다를 수 있습니다.
각각은 socat
다른 모든 멀티캐스트 피어에게 데이터를 보내고(터미널에 이것을 입력), 그들로부터 전송된 트래픽을 다시 읽습니다(그러나 자체에서 전송된 트래픽은 읽지 않습니다).