После того, как я сделаю широковещательную рассылку UDP, как мне узнать, на какой порт я вещал? - PullRequest
0 голосов
/ 11 января 2020

У меня есть приложение Linux C, которое должно использовать UDP. Сервер передает «пакет обнаружения» и затем прослушивает любые подключенные клиенты, чтобы ответить с подобным эхом. Используя порты, клиенты и сервер могут обмениваться данными, используя свои разные порты.

Вот как сервер передает свой пакет обнаружения:

int main() {
  puts("starting");
  int sock;
  int yes = 1;
  struct sockaddr_in broadcast_addr;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  char outbound_buffer[63];
  int i;

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error");
    return -1;
  }
  ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes));
  if (ret == -1) {
    perror("setsockopt error");
    return 0;
  }
  memset(outbound_buffer,0,sizeof(outbound_buffer));

  addr_len = sizeof(struct sockaddr_in);

  memset((void*)&broadcast_addr, 0, addr_len);
  broadcast_addr.sin_family = AF_INET;
  broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
  broadcast_addr.sin_port = htons(PORT);

  outbound_buffer[0] = 0xEF;
  outbound_buffer[1] = 0xFE;
  outbound_buffer[2] = 0x02;

    ret = sendto(sock, outbound_buffer, 63, 0, (struct sockaddr*) &broadcast_addr, addr_len);

Это прекрасно работает; клиент получает обнаружение и получает IP-адрес и порт сервера:

int main() {

  stoplink = 0;
  stopData = 0;
  int addr_len;
  int count;
  int ret;
  fd_set readfd;
  char buffer[1024];
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("sock error\n");
    return -1;
  }
  addr_len = sizeof(struct sockaddr_in);
  memset((void*)&server_addr, 0, addr_len);
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htons(INADDR_ANY);
  server_addr.sin_port = htons(PORT);

  ret = bind(sock, (struct sockaddr*)&server_addr, addr_len);
  if (ret < 0) {
    perror("bind error\n");
    return -1;
  }
  while (1) {

  puts("Initialized; await discovery");

    FD_ZERO(&readfd);
    FD_SET(sock, &readfd);

    ret = select(sock+1, &readfd, NULL, NULL, 0);
    if (ret > 0) {
      if (FD_ISSET(sock, &readfd)) {
        count = recvfrom(sock, buffer, 1024, 0, (struct sockaddr*)&client_addr, &addr_len);
        if((buffer[0] & 0xFF) == 0xEF && (buffer[1] & 0xFF) == 0xFE) {
      fprintf(stderr,"discovery packet detected\n"); 
          cmdport = ntohs(client_addr.sin_port);
          printf("\nClient connection information:\n\t IP: %s, Port: %d\n", 
            inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

       count = sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&client_addr,
         sizeof(client_addr));
        }
      }
    }

  puts("Now starting command processing loop");

Это также работает нормально ... но он отправляет ответ на порт на сервере, с которого пришла широковещательная рассылка - он был выбран случайным образом автоматически сервером; так как мне узнать, какой порт слушать на стороне сервера для получения ответа клиента?

Ответы [ 3 ]

1 голос
/ 12 января 2020

Серверу не нужно ничего делать. После отправки пакета порт на стороне сервера устанавливается.

Например, если клиент видит, что сообщение сервера пришло с порта 34567, то сокет сервера использует порт 34567. Тогда любые сообщения, отправленные на сервер через порт 34567, могут быть прочитаны этим же сокетом сервера.

Таким образом, сервер может просто позвонить recvfrom, и он получит ответ от клиента.

0 голосов
/ 16 января 2020

Спасибо за все комментарии. getsockname () - это то, что мне нужно.

0 голосов
/ 12 января 2020

Вы поменялись обычными значениями слов "клиент" и "сервер" - обычно сервер будет привязываться к указанному порту c и прослушивать (широковещательные) пакеты, в то время как клиент будет транслировать пакет обнаружения, чтобы найти сервер. Когда сервер получает широковещательную рассылку, он ответит клиенту, который просто сделает recv на своем (одном) сокете, чтобы получить ответ, который будет иметь IP-адрес сервера. Если может быть несколько серверов, то они все ответят клиенту, поэтому клиент увидит несколько ответов и должен будет выбрать из них. Но, самое главное, клиенту никогда не нужно знать, какой порт он использует - он просто позволяет системе выбрать для него неиспользуемый порт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...