Многоадресная рассылка в C macOS - PullRequest
2 голосов
/ 11 января 2020

Многоадресная рассылка между двумя приложениями на одном хосте (macOS). Пример основан на запуске 2 приложений Appli_A , которые присоединяются к одной и той же многоадресной группе и прослушивают входящий пакет дейтаграмм, который отправляется приложением Appli_B , но существует только одно из 2 приложения Appli_A получают пакет, а не оба. Поскольку реализация зависит от платформы, и я использую macOS, мне пришлось изменить некоторые команды, поэтому я использую SO_REUSEPORT вместо SO_REUSEADDRES Но это все равно не будет работать. Вот небольшой пример:

Appli_A

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct sockaddr_in localSock;
struct ip_mreq group;
int sd;
int datalen;
char databuf[1024];

void sigint_routine_handler(int param){
    if(close(sd) == 0)
        printf("hSocket closed\n");
    else
        printf("Error closing hSocket\n");

}


int main(int argc, char *argv[])
{
if(signal(SIGINT, sigint_routine_handler) == SIG_ERR)
    printf("ERROR: Installing suspend handler SIGINT\n");

sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
    perror("Opening datagram socket error");
    exit(1);
}

/* Enable SO_REUSEPORT to allow multiple instances of this */
/* application to receive copies of the multicast datagrams. */

int reuse = 1;
if(setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, (char *)&reuse, sizeof(reuse)) < 0)
{
    close(sd);
    exit(1);
}

/* Since I'm using htonl(INADDR_ANY) I'm Binding the socket to all available interfaces */
memset((char *) &localSock, 0, sizeof(localSock));
localSock.sin_family = AF_INET;
localSock.sin_port = htons(54011);
localSock.sin_addr.s_addr = htonl(INADDR_ANY);

if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock)))
{
    close(sd);
    exit(1);
}

/* Join the multicast group 235.73.158.23 */
group.imr_multiaddr.s_addr = inet_addr("235.73.158.23");
group.imr_interface.s_addr = htonl(INADDR_ANY);
if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0)
{
    close(sd);
    exit(1);
}

/* Read from the socket. */
datalen = sizeof(databuf);
if(read(sd, databuf, datalen) < 0)
{
    perror("Reading datagram message error");
    close(sd);
    exit(1);
}
else
{
    printf("Reading datagram message...OK.\n");
    printf("The message from multicast server is: \"%s\"\n", databuf);
}
if(close(sd) < 0)
        printf("Error close socket descriptio\n");

    return 0;
}

Appli_B

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

struct in_addr localInterface;
struct sockaddr_in groupSock;
int sd;
char databuf[50] = "Multicast test message$";
int datalen = sizeof(databuf);

int main(int argc, char *argv[])
{
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd < 0)
{
    perror("Opening datagram socket error");
    exit(1);
}
else
    printf("Opening the datagram socket...OK.\n");

memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
/* README Normally here should I specifiy the Multicast-adress of the group for the outgoing
   Datagrampacket, but it won't work if I specify this Multicast-adress "235.73.158.23"*/
groupSock.sin_addr.s_addr = htonl(INADDR_ANY);
groupSock.sin_port = htons(54011);

/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface -> I have checked the interface, it is Multicast capable */
localInterface.s_addr = inet_addr("192.168.1.5");
if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
    perror("Setting local interface error");
    exit(1);
}
else
    printf("Setting the local interface...OK\n");
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
int datalen = 50;
if(sendto(sd, databuf, datalen, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0){
    perror("Sending datagram message error");
}
else
    printf("Sending datagram message...OK\n");
return 0;
}

ОБНОВЛЕНИЕ

Я пробовал на Ubuntu linux 16.04, там все отлично работает. Я изменил SO_REUSEPORT на SO_REUSEADDR и Multicast-адрес исходящего Datagrampacket Appli_B на Multicastgroup, указанный в Appli_A, если я делаю это на MACOS, ни одно из 2 приложений Appli_A не получает пакет дейтаграммы, в случае, если интерфейс может не иметь многоадресной рассылки адрес, по которому я следовал, блог , но он все равно не будет работать под MacOS.

...