Я пишу пример кода на разных языках для отправки пакетов на локальный многоадресный адрес ipv6 link (ff02::fb), но это не всегда работает. версия питона:
#!/usr/bin/env python
MYPORT = 5353
MYGROUP_6 = 'ff02::fb'
MYTTL = 1 # Increase to reach other networks
import time
import struct
import socket
import sys
def main():
sender(MYGROUP_6)
def sender(group):
addrinfo = socket.getaddrinfo(group, None)[0]
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
# Set Time-to-live (optional)
ttl_bin = struct.pack('@i', MYTTL)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
while True:
data = repr(time.time())
s.sendto(data + '\0', (addrinfo[4][0], MYPORT))
time.sleep(1)
if __name__ == '__main__':
main()
этот работает в Linux (3.13.0-24-generic), но получает ошибку «нет маршрута к хосту» в OS X (10.10 Yosemite). Затем я пишу простую программу на Go, чтобы попробовать еще раз:
package main
import (
"fmt"
"net"
)
func main() {
addr, err := net.ResolveUDPAddr("udp6", "[ff02::fb]:5353")
if err != nil {
fmt.Printf("ResolveUDPAddr err: %v\n", err)
return
}
if conn, err := net.DialUDP("udp6", nil, addr); err == nil {
if _, err = conn.Write([]byte("hello")); err != nil {
fmt.Printf("Write failed, %v\n", err)
}
} else {
fmt.Printf("DialUDP err: %v\n", err)
}
return
}
этот получает ошибку «подключение: неверный аргумент» в Linux и ту же ошибку «нет маршрута к хосту» с примером выше в OS X. Наконец, я пробую низкоуровневый язык C:
/*
* Examples:
* >sender 224.0.22.1 9210 6000 1000
* >sender ff15::1 2001 65000 1
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h> /* for usleep() */
#define SOCKET int
int mcast_send_socket(char* multicastIP, char* multicastPort, int multicastTTL, struct addrinfo **multicastAddr) {
SOCKET sock;
struct addrinfo hints = { 0 }; /* Hints for name lookup */
/*
Resolve destination address for multicast datagrams
*/
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_NUMERICHOST;
int status;
if ((status = getaddrinfo(multicastIP, multicastPort, &hints, multicastAddr)) != 0 )
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return -1;
}
/*
Create socket for sending multicast datagrams
*/
if ( (sock = socket((*multicastAddr)->ai_family, (*multicastAddr)->ai_socktype, 0)) < 0 ) {
perror("socket() failed");
freeaddrinfo(*multicastAddr);
return -1;
}
/*
Set TTL of multicast packet
*/
if ( setsockopt(sock,
(*multicastAddr)->ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
(*multicastAddr)->ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
(char*) &multicastTTL, sizeof(multicastTTL)) != 0 ) {
perror("setsockopt() failed");
freeaddrinfo(*multicastAddr);
return -1;
}
/*
set the sending interface
*/
if((*multicastAddr)->ai_family == PF_INET) {
in_addr_t iface = INADDR_ANY; /* well, yeah, any */
if(setsockopt (sock,
IPPROTO_IP,
IP_MULTICAST_IF,
(char*)&iface, sizeof(iface)) != 0) {
perror("interface setsockopt() sending interface");
freeaddrinfo(*multicastAddr);
return -1;
}
}
if((*multicastAddr)->ai_family == PF_INET6) {
unsigned int ifindex = 0; /* 0 means 'default interface'*/
if(setsockopt (sock,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
(char*)&ifindex, sizeof(ifindex)) != 0) {
perror("interface setsockopt() sending interface");
freeaddrinfo(*multicastAddr);
return -1;
}
}
return sock;
}
static void DieWithError(char* errorMessage)
{
fprintf(stderr, "%s\n", errorMessage);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
SOCKET sock;
struct addrinfo *multicastAddr;
char* multicastIP; /* Arg: IP Multicast address */
char* multicastPort; /* Arg: Server port */
char* sendString; /* Arg: String to multicast */
int sendStringLen; /* Length of string to multicast */
int multicastTTL; /* Arg: TTL of multicast packets */
int defer_ms; /* miliseconds to defer in between sending */
int i;
if ( argc < 5 || argc > 6 )
{
fprintf(stderr, "Usage: %s <Multicast Address> <Port> <packetsize> <defer_ms> [<TTL>]\n", argv[0]);
exit(EXIT_FAILURE);
}
multicastIP = argv[1]; /* First arg: multicast IP address */
multicastPort = argv[2]; /* Second arg: multicast port */
sendStringLen = atoi(argv[3]);
defer_ms = atoi(argv[4]);
/* just fill this with some byte */
sendString = calloc(sendStringLen, sizeof(char));
for(i = 0; i<sendStringLen; ++i)
sendString[i]= 's';
multicastTTL = (argc == 6 ? /* Fourth arg: If supplied, use command-line */
atoi(argv[5]) : 1); /* specified TTL, else use default TTL of 1 */
sock = mcast_send_socket(multicastIP, multicastPort, multicastTTL, &multicastAddr);
if(sock == -1 )
DieWithError("mcast_send_socket() failed");
int nr=0;
for (;;) /* Run forever */
{
int* p_nr = (int*)sendString;
*p_nr = htonl(nr);
if ( sendto(sock, sendString, sendStringLen, 0,
multicastAddr->ai_addr, multicastAddr->ai_addrlen) != sendStringLen )
DieWithError("sendto() sent a different number of bytes than expected");
fprintf(stderr, "packet %d sent\n", nr);
nr++;
usleep(defer_ms*1000);
}
/* NOT REACHED */
return 0;
}
эта версия C также не работает в OS X, она жалуется «Не удается назначить запрошенный адрес» на setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char*)&ifindex, sizeof(ifindex))
, похоже, OS X не поддерживает автоматический выбор интерфейса.
РЕДАКТИРОВАТЬ: добавление идентификатора области (en0) заставляет версию go & C работать на OS X, но версия python (2.7.6) по-прежнему жалуется: «Нет маршрута к хосту».
ff12::fb
вместоff02::fb
, который прописан для mDNSv6. См. этот ответ, чтобы узнать, решает ли ответ вашу проблему. - person Ron Maupin   schedule 11.04.2020