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:
Przy braku argumentów startowych efekt będzie taki:
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 Na razie działa, nie wymaga poprawek, a wiadomo, lepsze jest wrogiem dobrego.
Pozdrawiam