LINUX.ORG.RU

UDP-клиент

 


0

2

Здравствуйте.

Возник вопрос следующего характера. Есть домашняя сеть состоящая из роутера (wl500, прошивка tomato) и трёх подключённых к нему компьютеров (линукс).

Адрес роутера 192.168.5.99, компьютеры получают адреса по dhcp (192.168.5.197, 192.168.5.224, 192.168.5.234).

На компах крутятся udp-сервера.

Что хочу

Хочу чтоб на роутере работал udp-клиент и отправлял ВСЕМ компам некий пакет (просто строка символов).

Вот сам udp-клиент:

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

#define SERVERPORT "3492"    

int main(int argc, char *argv[])
{
    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    int numbytes;
    int n=1;

    if (argc != 2) {
        exit(1);
    }

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_DGRAM;
    

    if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

   
    for(p = servinfo; p != NULL; p = p->ai_next) 
     {
        if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) 
          {
            continue;
          }

        break;
     }

    setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,&n,sizeof(n)); 

    if (p == NULL) {
        return 2;
    }


    char str_iz_file[128] = {0,};

    while (1) 
      {
          usleep(910000);  

          FILE *f; 
          f = fopen("/tmp/file.db", "r"); // tmp
          if(f == NULL) 
            {
              continue;
            } 

           fgets(str_iz_file, 127, f);
           fclose(f); 


           if ((numbytes = sendto(sockfd, str_iz_file, strlen(str_iz_file), 0, p->ai_addr, p->ai_addrlen)) == -1) {
           
           exit(1);
           }

           printf("bla-bla: %s\n", str_iz_file);

           memset(str_iz_file, 0, sizeof(str_iz_file));

      }

    freeaddrinfo(servinfo);
  
    close(sockfd);

    return 0;
}

//gcc -W -Wall udpclient.c -o udpclient
//  make package/udpclient/compile V=s
// ./udpclient 255.255.255.255

Запускаю вот так: ./udpclient 255.255.255.255

Вопрос заключается в том, что если запускать udpclient на одном из компов, то всё отлично, другие компы получают пакет, а вот если запустить его на роутере, то никто ничего не получает.

Объясните пожалуйста, что я делаю не так?


Объясните пожалуйста, что я делаю не так?

не читаете документацию, попробуйте прочитать про 255.255.255.255

hizel ★★★★★
()
Ответ на: комментарий от stD

Вкратце - тебе нужен широковещательный адрес твоей локальной сети; ЕМНИП, 255.255.255.255 работает как широковещательный адрес той сети, в которой расположен маршрут по умолчанию, поэтому на твоих компах работает (там маршрут через роутер), а на роутере не работает (там маршрут через провайдера).

P.S. хотя в RFC говорится немного другое:

The address 255.255.255.255 denotes a broadcast on a local hardware network that must not be forwarded.

Не совсем понятно, какое именно local hardware имеется в виду - первое, с маршрутом по умолчанию или все. Можешь попробовать посниффить трафик на предмет того, отправляет вообще ли роутер пакет куда-нибудь, или нет.

tiandrey ★★★★★
()
Последнее исправление: tiandrey (всего исправлений: 3)
Ответ на: комментарий от tiandrey

Благодарствую, это многое проясняет.

Не сочтите за труд, расскажите как бы вы сделали, если бы понадобилось отправлять такой же пакет, только не в локальную сеть, а наружу, в интернет, например на смартфон. Иными словами, есть ли возможность найти в глобальной паутине смартфон и передать ему udp-пакет?

stD
() автор топика
Ответ на: комментарий от stD

Используй третью сторону, иначе никак.

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

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Благодарю. Обажаю телескопы.

stD
() автор топика
Ответ на: комментарий от stD

Ты что, какие нафиг глобальные броадкасты :) Сеть зафлудится.

Третья сторона не обязательна, если у твоего сервера внешний адрес (не обязательно статический, всегда dyndns можно настроить). Смартфон должен периодически подключаться к серверу, а дальше есть несколько вариантов.

Либо сервер просто запоминает адрес смартфона (получается тот же dyndns своими силами), но этот вариант совсем не вариант, если у телефона нет внешнего адреса (например, подключен к WiFi и находится за NAT).

Либо смартфон подключается к серверу и запрашивает у него данные.

В общем случае невозможно отправить IP-пакет напрямую на смартфон, даже с использованием третьей стороны (если не делать VPN на смартфоне). Кстати, да, VPN - ещё одно решение, сможешь напрямую со смартфоном общаться.

Также посмотри в сторону push-уведомлений (Google Cloud Messaging в случае Android и Apple Push Notifications в случае iOS).

tiandrey ★★★★★
()
Последнее исправление: tiandrey (всего исправлений: 2)

Сокет надо бы биндить на адрес того интерфейса, с которого ты хочешь посылать бродкаст. На роутере это 192.168.5.99. Посылать надо на 255.255.255.255:3492.

В интернет надо посылать только юникаст. Значит надо знать адрес получателя. Получатель может опубликовать свой адрес в DNS, например, с помощью какого-нибудь сервиса dynamic dns. Если у получателя нет белого адреса, послать ему ничего не удастся. Если только NAT-бокс, за которым находится получатель, не сделает проброс порта. Проброс порта может быть настроен на NAT-боксе статически или открываться по запросу (UPnP-IGD, NAT-PMP, SOCKS, etc.).

iliyap ★★★★★
()
Ответ на: комментарий от iliyap

Огромное спасибо за ответы, в двух постах написано больше, чем в прочитанных мною десяти статьях «ниочём».

Наверное VPN наиболее удачное решение, сразу двух зайцев...

stD
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.