Многоадресная рассылка между двумя приложениями на одном хосте (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.