2015-11-14 1 views
3

Конец цель:Как проверить, присоединился ли клиент к группе многоадресной рассылки?

Для родительского процесса сервера, чтобы знать, какие клиенты присоединиться или покинуть группу многоадресной рассылки. До сих пор я только пытался проверить присоединение клиентов, поскольку я полагаю, что проверка того, кто уходит, - это аналогичный вопрос.

Мой метод (ы) до сих пор:

Проверка на наличие изменений в гнездо группы многоадресной передачи через select().

После присоединения клиент выполняет команду sendto(), направленную на (родительский процесс) серверной программы. select() на сервере предназначен для распознавания любых изменений, но, по-видимому, нет, и поэтому retval != 0 никогда не будет истинным.

Результатов до сих пор

Я Пытался с различными IP-адресами и константами, такими как INADDR_ANY, но я сумел только до отправки сообщения обратно клиента через многоадресную рассылку, и это один интерпретируйте его так, как будто серверная программа отправила его. Наиболее распространенным результатом является то, что серверная программа вообще не получает никакого сообщения.

Вот мой код клиента:

/* Receiver/client multicast Datagram*/ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

#define MAX_MSG 100 

struct sockaddr_in localSock, servSock; 
struct ip_mreq group; 
int sd, n; 
int datalen, mcastport; 
char msg[MAX_MSG]; 

int main(int argc, char *argv[]) 
{ 

    if(argc!=3) { 
     printf("usage : %s <address> <port>\n",argv[0]); 
     exit(0); 
    } 

    mcastport = atoi(argv[2]); 


    /* Create a datagram socket on which to receive. */ 
    sd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(sd < 0) 
    { 
     perror("Opening datagram socket error"); 
     exit(1); 
    } 
    else 
     printf("Opening datagram socket....OK.\n"); 

    /* Enable SO_REUSEADDR to allow multiple instances of this */ 
    /* application to receive copies of the multicast datagrams. */ 
    { 
     int reuse = 1; 
     if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) 
     { 
      perror("Setting SO_REUSEADDR error"); 
      close(sd); 
      exit(1); 
     } 
     else 
      printf("Setting SO_REUSEADDR...OK.\n"); 
    } 

    /* Bind to the proper port number with the IP address */ 
    /* specified as INADDR_ANY. */ 
    memset((char *) &localSock, 0, sizeof(localSock)); 
    localSock.sin_family = AF_INET; 
    localSock.sin_port = htons(mcastport); 
    localSock.sin_addr.s_addr = INADDR_ANY; 
    if(bind(sd, (struct sockaddr*)&localSock, sizeof(localSock))) 
    { 
     perror("Binding datagram socket error"); 
     close(sd); 
     exit(1); 
    } 
    else 
     printf("Binding datagram socket...OK.\n"); 

    printf("Enter the group's name you want to join:\n"); 
    scanf("%s", msg); 

    /* Join the multicast group 226.1.1.1 on the local IP address */ 
    /* interface. Note that this IP_ADD_MEMBERSHIP option must be */ 
    /* called for each local interface over which the multicast */ 
    /* datagrams are to be received. */ 
    group.imr_multiaddr.s_addr = inet_addr(argv[1]); 
    group.imr_interface.s_addr = inet_addr("127.0.0.1"); 
    if(setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&group, sizeof(group)) < 0) 
    { 
     perror("Adding multicast group error"); 
     close(sd); 
     exit(1); 
    } 
    else 
     printf("Adding multicast group...OK.\n"); 

    /* Initialize the group sockaddr structure with a */ 
    /* group address of 226.1.1.1 and port given by user. */ 
    memset((char *) &servSock, 0, sizeof(servSock)); 
    servSock.sin_family = AF_INET; 
    servSock.sin_addr.s_addr = inet_addr(argv[1]); 
    servSock.sin_port = htons(mcastport); 

    if(sendto(sd, "", 1, 0, (struct sockaddr*) &servSock, sizeof(servSock)) < 0) 
    {perror("Sending datagram message error");} 
    else 
     printf("Sending datagram message...OK\n"); 

    /* Read from the socket. */ 
    if((n=read(sd, msg, MAX_MSG)) < 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", msg); 
    } 

    msg[n] = '\0'; 

    return 0; 
} 

Это моя программа сервера код:

/* Send Multicast Datagram code*/ 
#include <sys/types.h> 
#include <sys/ioctl.h> 
#include <net/if.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> /* for strncpy, memset */ 

#define MAX_MSG 100 

struct in_addr localInterface; 
struct sockaddr_in groupSock, cliAddr; 
int sd, mcastport, maxJoin, maxJoined = 0, pipefd[2], cliLen, cpid; 
char msg[MAX_MSG], groupName[MAX_MSG]; 

int main (int argc, char *argv[ ]) 
{ 


    /* check command line args */ 
    if(argc < 2) { 
     printf("usage : %s <port> \n", argv[0]); 
     exit(1); 
    } 

    mcastport = atoi(argv[1]); 

    /* 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"); 

    /* Initialize the group sockaddr structure with a */ 
    /* group address of 225.1.1.1 and port given by user. */ 
    memset((char *) &groupSock, 0, sizeof(groupSock)); 
    groupSock.sin_family = AF_INET; 
    groupSock.sin_addr.s_addr = inet_addr("226.1.1.1"); 
    groupSock.sin_port = htons(mcastport); 

    printf("Create a group: "); 
    scanf("%s", groupName); 

    printf("Maximum number of clients that can join the group? "); 
    scanf("%d", &maxJoin); 

    /* Disable loopback so you do not receive your own datagrams. 
    { 
    char loopch = 0; 
    if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0) 
    { 
    perror("Setting IP_MULTICAST_LOOP error"); 
    close(sd); 
    exit(1); 
    } 
    else 
    printf("Disabling the loopback...OK.\n"); 
    } 
    */ 

    /* Set local interface for outbound multicast datagrams. */ 
    /* The IP address specified must be associated with a local, */ 
    /* multicast capable interface. */ 
    printf("Setting the local interface..."); 
    localInterface.s_addr = inet_addr("127.0.0.1"); 
    if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0) 
    { 
     perror("error"); 
     exit(1); 
    } 
    else 
     printf("OK\n"); 



    if((cpid = fork()) == 0) //child process --sends messages 
    { 
     /* Send a message to the multicast group specified by the*/ 
     /* groupSock sockaddr structure. */ 
     printf("Enter a message to send: \n"); 
     scanf("%s", msg); 

     if(sendto(sd, msg, strlen(msg)+1, 0, (struct sockaddr*)&groupSock, sizeof(groupSock)) < 0) 
     {perror("Sending datagram message error");} 
     else 
      printf("Sending datagram message...OK\n"); 

     /* Try the re-read from the socket if the loopback is not disable 
     if(read(sd, databuf, datalen) < 0) 
     { 
     perror("Reading datagram message error\n"); 
     close(sd); 
     exit(1); 
     } 
     else 
     { 
     printf("Reading datagram message from client...OK\n"); 
     printf("The message is: %s\n", databuf); 
     } 
     */ 

     exit(EXIT_SUCCESS); 
    } 
    else //parent process --checks for JOINs and QUITs 
    { 
     fd_set rfds; 
     struct timeval tv; 
     int retval, status; 

     while (waitpid(cpid, &status, WNOHANG) != cpid) 
     { 
      /* Watch stdin (fd 0) to see when it has input. */ 
      FD_ZERO(&rfds); 
      FD_SET(sd, &rfds); 

      /* Wait up to five seconds. */ 
      tv.tv_sec = 5; 
      tv.tv_usec = 0; 

      retval = select(sd+1, &rfds, NULL, NULL, &tv); 
      /* Don't rely on the value of tv now! */ 

      if (retval == -1) 
       perror("select()"); 
      else if (retval != 0) 
      { 
       printf("Data is available now.\n"); 
       /* FD_ISSET(0, &rfds) will be true. */ 

       cliLen = sizeof(cliAddr); 
       int n; 
       if((n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr,&cliLen)) == -1) 
        perror("Some bullshit happened"); 
       msg[n] = '\0'; 

       printf("Client IP:port is: %s:%d", inet_ntoa(cliAddr.sin_addr), (int) ntohs(cliAddr.sin_port)); 
      } else 
      {printf("no data.\n");} 
     } 
     exit(0); 
    } 
    return 0; 
} 

Возможные решения я не пробовал: Может быть, я не должен использовать многоадресную группа для отправки информации client-> server, а скорее другого типа подключения? Я просто догадываюсь. Я знаю, что вы, ребята, не любите заниматься чьей-то работой.

Я был в этой «простой» проблеме в течение нескольких часов и пробовал читать везде, где мог, в том числе this question, который кажется очень похожим, но мне это никак не удалось. Я совершенно поражаю здесь.

ответ

1

Если клиент отправляет в группу многоадресной передачи, и сервер ожидает, что он прочитает это, сервер также должен присоединиться к группе многоадресной рассылки.

Это не отличное решение, так как все остальные члены-клиенты также получат эту многоадресную рассылку.

Было бы больше смысла для клиента на первом получить многоадресного от сервера, а затем реагировать на адрес сервера, который обеспечивается с помощью результирующих аргументов recvfrom().

+0

во втором решении, которое вы предлагаете, отправит ли клиент sendto() или другой метод? – Yokhen

+1

С 'sendto()' или 'sendmsg()'. – EJP

1

Две точки, которые могут помочь вам:

  • Там нет необходимости использовать многоадресную, если ваше сообщение только местные (вы используете 127.0.0.1 в вашем коде)
  • Multicast группы соединены сетевыми интерфейсами , а не процессами. Когда сетевой интерфейс присоединился к многоадресному интерфейсу, второе соединение одного и того же сетевого интерфейса с одной и той же группой многоадресной передачи ничего не изменит. Даже если это еще один процесс на том же хосте, который запрашивает второе соединение .
+0

Все это симуляция для учебных целей, но спасибо за указание первого элемента. Я вернусь к вам по второму пункту. Не уверен, что это значит. – Yokhen