[µKod] Sposób na znajdywanie własnych urządzeń w sieci LAN

Projekty użytkowników forum zarówno sprzętowe, jak i związane z programowaniem w dowolnym języku.
Awatar użytkownika
inż.wielki
User
User
Posty: 209
Rejestracja: niedziela 20 gru 2015, 23:11

[µKod] Sposób na znajdywanie własnych urządzeń w sieci LAN

Postautor: inż.wielki » sobota 10 lut 2018, 21:50

Często podłączając urządzenie do sieci LAN, co chwila trzeba sprawdzać jaki ma adres IP. Czy to poprzez informacje via UART, wyświetlacz, lub też listę dostępnych urządzeń po zalogowaniu się do kontrolera sieci. Zaczęło mnie to męczyć, więc wymyśliłem uniwersalny pomysł. Zaimplementowałem go na ESP, orange PI czy Raspberry Pi. Postanowiłem się nim podzielić, sam zamysł jest banalnie prosty. Postawiony serwer UDP, czeka na konkretny ciąg znaków, na konkretnym porcie. W momencie jak go otrzyma, po prostu wysyła informację zwrotną z nazwą "projektu", albo urządzenia wraz z własnym adresem IP. W tym wypadku prezentowany kod jest skrobnięty na malinkę. Korzysta ona z linuxowych soketów. W projekcie z ESP12/32 wykorzystuje SDK RTOS od producenta i tam korzystam z funkcjonalności LWiP.

Przechodząc do rzeczy. Kod prezentuje się następująco:

Kod: Zaznacz cały

#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netdb.h>
#include<ifaddrs.h>
#include<unistd.h>
 
#define BUFLEN 512  //Max length of buffer
#define PORT 1994   //The port on which to listen for incoming data

#define DEVICE_NAME "Some device"
#define SEARCH_STRING "find devices"
#define RESPONSE_STRING "%s there, from: %s!"

void die(char *s)
{
    perror(s);
    exit(1);
}

void getIp( unsigned char *_ip)
{
    FILE *f;
    char line[100] , *p , *c;

    f = fopen("/proc/net/route" , "r");

    while(fgets(line , 100 , f))
    {
        p = strtok(line , " \t");
        c = strtok(NULL , " \t");

        if(p!=NULL && c!=NULL)
        {
            if(strcmp(c , "00000000") == 0)
            {
                printf("Default interface is : %s \n" , p);
                break;
            }
        }
    }

    //which family do we require , AF_INET or AF_INET6
    int fm = AF_INET;
    struct ifaddrs *ifaddr, *ifa;
    int family , s;
    char host[NI_MAXHOST];
   
    if (getifaddrs(&ifaddr) == -1)
    {
        perror("getifaddrs");
        exit(EXIT_FAILURE);
    }

    //Walk through linked list, maintaining head pointer so we can free list later
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
    {
        if (ifa->ifa_addr == NULL)
        {
            continue;
        }

        family = ifa->ifa_addr->sa_family;

        if(strcmp( ifa->ifa_name , p) == 0)
        {
            if (family == fm)
            {
                s = getnameinfo( ifa->ifa_addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6) , host , NI_MAXHOST , NULL , 0 , NI_NUMERICHOST);

                if (s != 0)
                {
                    printf("getnameinfo() failed: %s\n", gai_strerror(s));
                    exit(EXIT_FAILURE);
                }

                printf("address: %s\n", host);
                strcpy(_ip, host);
            }
            printf("\n");
        }
    }

    freeifaddrs(ifaddr);
}

int main(int argc , char *argv[])
{
    struct sockaddr_in si_me, si_other;

    int s, i, slen = sizeof(si_other) , recv_len;
    char buf[BUFLEN];
    char host[NI_MAXHOST];     
    char response[BUFLEN];
    char deviceName[BUFLEN];

    if( argc < 2 )
    {
        sprintf(deviceName, DEVICE_NAME);
    }
    else if (argc == 2)
    {
        sprintf(deviceName, argv[1]);
    }

    //create a UDP socket

    if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
    {
        die("socket");
    }
     
    // zero out the structure
    memset((char *) &si_me, 0, sizeof(si_me));
     
    si_me.sin_family = AF_INET;
    si_me.sin_port = htons(PORT);
    si_me.sin_addr.s_addr = htonl(INADDR_ANY);
     
    //bind socket to port
    if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
    {
        die("bind");
    }
   
    //get IP using on local machine
    getIp(host);

    while(1)
    {
        //try to receive some data, this is a blocking call
        if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1)
        {
            die("recvfrom()");
        }

        if(strcmp(buf, SEARCH_STRING) == 0)
        {
        //now reply the client with the same data
            sprintf(response, RESPONSE_STRING, deviceName, host);
            if (sendto(s, response, strlen(response), 0, (struct sockaddr*) &si_other, slen) == -1)
            {
                die("sendto()");
            }
   
        }

    }
 
    close(s);
    return 0;
}


Uruchomienie jest banalnie proste. Po kompilacji należy uruchomić serwer, należy podać parametr, który określa nazwę urządzenia.

Kod: Zaznacz cały

gcc udp_search.c -o search_devices && ./search_devices test

Efekt:
Screenshot_20180210_214515.png


Przy braku argumentów startowych efekt będzie taki:
Screenshot_20180210_214639.png


Te 3 definicje, określają ciąg znaków w formie stringu, który będzie szukany w pakietach, domyślna nazwa urządzenia, oraz format odpowiedzi.

Kod: Zaznacz cały

#define DEVICE_NAME "Some device"
#define SEARCH_STRING "find devices"
#define RESPONSE_STRING "%s there, from: %s!"


No i to by było na tyle :) Zaznaczam że kod nie jest idealny, jest generalnie odpowiednio spreparowaną sklejką kodów znalezionych na stackoverflow :D Na razie działa, nie wymaga poprawek, a wiadomo, lepsze jest wrogiem dobrego.

Pozdrawiam
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony poniedziałek 12 lut 2018, 20:38 przez inż.wielki, łącznie zmieniany 1 raz.

Awatar użytkownika
squeez
User
User
Posty: 191
Rejestracja: czwartek 04 lut 2016, 10:13

Re: [µProjekt] Sposób na znajdywanie własnych urządzeń w sieci LAN

Postautor: squeez » poniedziałek 12 lut 2018, 08:49

kiedyś też się tym martwiłem, miałem na to kilka rozwiązań:
1) korzystanie z statycznych IP - trochę upierdliwe jak się zmienia adresację sieci itp.
2) przydzielanie IP na podstawie MAC - proste i skuteczne ale trzeba wykonać dodatkową pracę (na routerze połączyć skorelować MAC i IP).
3) w ESP nadaję każdemu modułowi inny hostname, te informację są wówczas dostępne i zamiast po IP można po hostname się odwoływać albo "uzyskać" IP na podstawie hostname
4) obecnie w swoich modułach/projektach wykorzystuję protokół MQTT i adresacja IP niejako mnie wcale nie interesują w normalnej pracy a dla nienormalnej (jak chcę zmienić soft przez OTA) IP uzyskuję właśnie z hostname.

Plusy tego takie że są to niejako pasywne metody tzn nie trzeba nić pisać na ESP, ustawiać serwera, słuchać na porcie, odpowiadać na zapytania itp.

Ale to takie luźne uwagi może komuś do czegoś się przydadzą, generalnie można uznać że każda metoda jest poprawna jeśli prowadzi do osiągnięcia celu.

Awatar użytkownika
inż.wielki
User
User
Posty: 209
Rejestracja: niedziela 20 gru 2015, 23:11

Re: [µProjekt] Sposób na znajdywanie własnych urządzeń w sieci LAN

Postautor: inż.wielki » poniedziałek 12 lut 2018, 09:02

Przy MQTT faktycznie nie ma to żadnego sensu. Ale ja na razie z tego nie korzystam, więc to mi się przydaje. Poza tym, potem bardzo łatwo jest sterować wszystkimi urządzeniami za pomocą np jednego programu, który odpowiednio wyszuka dane urządzenia.

Awatar użytkownika
ZbeeGin
User
User
Posty: 212
Rejestracja: sobota 08 lip 2017, 17:16
Lokalizacja: GOP
Kontaktowanie:

Re: [µProjekt] Sposób na znajdywanie własnych urządzeń w sieci LAN

Postautor: ZbeeGin » poniedziałek 12 lut 2018, 18:01

Cóż. Projekt powinien być raczej zaliczony do serii µKod, ale nie będę niczego wymagać. :P

Awatar użytkownika
inż.wielki
User
User
Posty: 209
Rejestracja: niedziela 20 gru 2015, 23:11

Re: [µProjekt] Sposób na znajdywanie własnych urządzeń w sieci LAN

Postautor: inż.wielki » poniedziałek 12 lut 2018, 20:37

ZbeeGin pisze:Cóż. Projekt powinien być raczej zaliczony do serii µKod, ale nie będę niczego wymagać. :P


dobry pomysł :)


Wróć do „DIY”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość