[C] gethostbyname() programmazione client/server

mark9

Nuovo Utente
45
3
Sto cercando di capire il funzionamento della funzione gethostbyname() per implementare in un programmino client la risoluzione dell'indirizzo del server attraverso il suo nome. L'esempio che ho è questo:


Codice:
const char * name = "localhost";
struct hostent *host;
host = gethostbyname(name);
if (host == NULL) {
fprintf(stderr, "gethostbyname() failed.\n");
return 0;
} else {
unsigned long ul = *((unsigned long *)host->h_addr_list[0]);
fprintf(stdout, "Risultato di gethostbyname(%s): %lu\n",name, ul);
struct in_addr NewAddr;
NewAddr.s_addr=ul;
printf("Indirizzo nella forma corretta: %s \n", inet_ntoa(NewAddr));
}

Quando poi vado a costruire l'indirizzo a cui connettermi, dovrei utilizzare la variabile "ul" così?

sad.sin_family = AF_INET; // sad è la struttura sockaddr_in
sad.sin_port = htons (porta); // porta è un numero di porta
sad.sin_addr.s_addr = inet_addr (ul); //inet_addr qui dovrebbe ricevere l'indirizzo "ul" sopra ricavato

Grazie per le delucidazioni.
 

dovah

Utente Attivo
199
47
Ciao,
dovrebbe funzionare.

sockaddr_in.sin_addr è di tipo struct in_addr; sin_addr.s_addr è di tipo long.
Quindi non hai bisogno di fare il cast in unsigned long e non hai bisogno di usare inet_addr su ul.

Ho provato in vari modi e addirittura potresti fare il cast di hostent.h_addr direttamente in struct in_addr.
Ti lascio due esempi:
Codice:
const char *name = "...";
struct hostent *host = gethostbyname(name);

// primo esempio: cast di h_addr in struct in_addr
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr = *((struct in_addr *) host->h_addr);
addr.sin_port = htons(port);

// secondo esempio: cast di h_addr in long
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = *((long *) host->h_addr);
addr.sin_port = htons(port);

p.s. h_addr è definito come costante ed equivale a h_addr_list[0].
p.p.s. non ho messo il controllo su host == NULL per motivi pratici, meglio non dimenticarlo però
 

mark9

Nuovo Utente
45
3
Quindi il pezzo di codice nel client dovrebbe essere, avendo supposto che voglio "tradurre" localhost in 127.0.0.1 (che è l'indirizzo del codice server):

Codice:
const char * name = "localhost";
    struct hostent *host;
    host = gethostbyname(name);
    if (host == NULL) {
    fprintf(stderr, "gethostbyname() failed.\n");
    return 0;
    } else {
    //unsigned long ul = *((unsigned long *)host->h_addr_list[0]);

        struct sockaddr_in sad;
        memset (&sad, 0, sizeof(sad));
        sad.sin_family = AF_INET;
        sad.sin_addr.s_addr = *((long*) host->h_addr);
        sad.sin_port = htons (port);

    }

Non mi riconosce poi però la struttura sad nel "connect" e non capisco perchè.
Se ti è più comodo ti posto l'intero codice. Ti ringrazio!
 

mark9

Nuovo Utente
45
3
Ecco, è un programma in cui nel client viene chiesto di inserire un numero e finchè questo sarà minore o uguale a 100, il server chiederà di inserirne un altro. Compilo su Eclipse.

Server:

Codice:
#if defined WIN32
#include <winsock2.h>
#else
#define closesocket close
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 30

void ClearWinSock() {
#if defined WIN32
    WSACleanup();
#endif
}

int main(void) {

//---------------------------INIZIALIZZAZIONE WSADATA

#if defined WIN32

    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf ("Error at WSAStartup");
        return 0;
    }

#endif

//-------------------------------CREAZIONE SOCKET

  int Mysocket;
  Mysocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (Mysocket < 0) {
      printf("socket creation failed\n");
      return 0;
  }

  struct sockaddr_in sad;
  memset(&sad, 0, sizeof(sad));
  sad.sin_family = AF_INET;
  sad.sin_addr.s_addr = inet_addr ("127.0.0.1");
  sad.sin_port = htons (9888);

//------------------------ASSEGNAZIONE PORTA E IP ALLA SOCKET

if (bind(Mysocket, (struct sockaddr*) &sad, sizeof(sad)) <0) {
    printf ("bind() failed\n");
    closesocket(Mysocket);
    return 0;
}

//---------------------------SETTAGGIO SOCKET ALL'ASCOLTO

int qlen = 10;

if (listen (Mysocket, qlen) < 0) {

    printf("listen() failed\n");
    closesocket(Mysocket);
    return 0;
}

struct sockaddr_in cad;
int Csocket;
int clientlen;

//------------------------------ACCETTA LA CONNESSIONE

while (1) {

    printf("In attesa di un client con cui comunicare\n");
    memset(&cad, 0, sizeof(cad));
    clientlen = sizeof(cad);

    if((Csocket = accept(Mysocket, (struct sockaddr*) &cad, &clientlen)) < 0) {
        printf ("accept failed\n");
        closesocket(Mysocket);
        ClearWinSock();
        return 0;
    }

    printf("connesso con -localhost-\n");

//-----------------------------------------INVIO STRINGA AL CLIENT

    char* inputString = "connessione avvenuta";
    int stringlen = strlen(inputString);


    if (send(Csocket, inputString, stringlen, 0) != stringlen) {
        printf("client-send() sent a different number of bytes than expected");
        closesocket(Csocket);
        ClearWinSock();
        system ("pause");
        return 0;
    }

//------------------------------------RICEZIONE PRIMA STRINGA DAL CLIENT

    char str1[BUFSIZE]; int a;

    do {

    int read = recv(Csocket, str1, BUFSIZE-1, 0);

    str1[read] = '\0';

    a= atoi(str1);

    printf("client scrive %d \n", a);

/*-----------------------------------------CONTROLLO DEL NUMERO RICEVUTO: se è minore o uguale a 100 invia al client
                                                                          "continua", altrimenti "quit" */

    if (a<=100) {

        char* sendmsg = "continua";

                int sendmsglen = strlen(sendmsg);
                send(Csocket, sendmsg, sendmsglen, 0);
    }

    else if (a>100) {

        char* sendmsg = "quit - uscita";

                int sendmsglen = strlen(sendmsg);
                send(Csocket, sendmsg, sendmsglen, 0);
    }


   } while (a<=100);

}

//----------------------------CHIUSURA CONNESSIONE

    printf ("\n");
    closesocket (Csocket);
    system ("pause");
    ClearWinSock();
    return 0;

}


Client:

Codice:
#if defined WIN32
#include <winsock2.h>
#else
#define closesocket close
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 30

void ClearWinSock() {
#if defined WIN32
    WSACleanup();
#endif
}

//-----------------------------INIZIALIZZAZIONE WSADATA

int main (void) {
#if defined WIN32

    WSADATA wsaData;
    int iResult = WSAStartup (MAKEWORD (2,2), &wsaData);

    if (iResult !=0) {
        printf ("error at WSASturtup\n");
        return 0;
        }

#endif

//--------------------------------CREAZIONE SOCKET

    int Csocket;

    Csocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (Csocket < 0) {

    printf ("socket creation failed");
    closesocket (Csocket);
    ClearWinSock();
    return 0;
    }

 //--------------------------COSTRUZIONE INDIRIZZO SERVER


    /*char ind[BUFSIZE];
    printf ("Inserisci indirizzo a cui connetterti\n");
    scanf ("%s", ind);*/

    int port;
    printf ("Inserisci porta a cui connetterti\n");
    scanf("%d", &port);


    const char * name = "localhost";
    struct hostent *host;
    host = gethostbyname(name);
    if (host == NULL) {
    fprintf(stderr, "gethostbyname() failed.\n");
    return 0;
    } else {


        struct sockaddr_in sad;
        memset (&sad, 0, sizeof(sad));
        sad.sin_family = AF_INET;
        sad.sin_addr.s_addr = *((long*) host->h_addr);
        sad.sin_port = htons (port);

    }

//------------------------------CONNESSIONE AL SERVER

  if (connect(Csocket, (struct sockaddr*) &sad, sizeof(sad)) < 0) {
      printf ("failed to connect\n");
      closesocket (Csocket);
      ClearWinSock();
      return 0;
  }

//-----------------------------RICEZIONE DATI DAL SERVER

  char buf[BUFSIZE];

  int read = recv (Csocket, buf, BUFSIZE - 1, 0);

if (read <=0) {

    printf ("Qualcosa non và!\n");
}

else {
    buf[read] = '\0';
    printf("Server scrive: %s\n", buf);
}

//----------------------------INVIO PRIMA STRINGA AL SERVER

int a; char astr[BUFSIZE];

do {

printf("inserisci un intero:\n");
scanf("%d", &a);

itoa(a, astr, 10);

int astrlen = strlen(astr);


if (send(Csocket, astr, astrlen, 0) != astrlen) {
    printf("client-send() sent a different number of bytes than expected");
    closesocket(Csocket);
    ClearWinSock();
    system ("pause");
    return 0;
}

//----------------------------RICEZIONE RISPOSTA SERVER

char buf2[BUFSIZE];

  int read2 = recv (Csocket, buf2, BUFSIZE - 1, 0);

if (read2 <=0) {

    printf ("Qualcosa non và!\n");
}

else {
    buf[read2] = '\0';
    printf("Server scrive: %s\n", buf2);
}

} while (a<=100);


//---------------------------------------CHIUSURA CONNESSIONE

printf ("\n");
closesocket (Csocket);
system ("pause");
ClearWinSock();
return 0;

}

Mi sfuggirà qualcosa dopo le modifiche fatte per l'utilizzo della gethostbyname(). Grazie.
 

dovah

Utente Attivo
199
47
Ricevi qualche errore in fase di compilazione o esecuzione?
p.s. ah ecco, ora ho notato.
hai dichiarato struct sockaddr_in sad in uno scope non visibile all'esterno.
Visto che nel caso in cui host == NULL fai un return, puoi omettere l'else.

In questo modo:
Codice:
//--------------------------COSTRUZIONE INDIRIZZO SERVER


    /*char ind[BUFSIZE];
    printf ("Inserisci indirizzo a cui connetterti\n");
    scanf ("%s", ind);*/

    int port;
    printf ("Inserisci porta a cui connetterti\n");
    scanf("%d", &port);


    const char * name = "localhost";
    struct hostent *host;
    host = gethostbyname(name);
    if (host == NULL) {
    fprintf(stderr, "gethostbyname() failed.\n");
    return 0;
    }


    struct sockaddr_in sad;
    memset (&sad, 0, sizeof(sad));
    sad.sin_family = AF_INET;
    sad.sin_addr.s_addr = *((long*) host->h_addr);
    sad.sin_port = htons (port);
 
Ultima modifica:

mark9

Nuovo Utente
45
3
Perfetto, era quello il problema, inoltre l'ho modificato nuovamente per fare in modo che "localhost" glielo scriva io:

Codice:
char ind[BUFSIZE];
    printf ("Inserisci indirizzo a cui connetterti\n");
    scanf ("%s", ind);

    int port;
    printf ("Inserisci porta a cui connetterti\n");
    scanf("%d", &port);


    struct hostent *host;
    host = gethostbyname(ind);
    if (host == NULL) {
    fprintf(stderr, "gethostbyname() failed.\n");
    return 0;
    }

        struct sockaddr_in sad;
        memset (&sad, 0, sizeof(sad));
        sad.sin_family = AF_INET;
        sad.sin_addr.s_addr = *((long*) host->h_addr);
        sad.sin_port = htons (port);

Solo non capisco perchè quando il client visualizza il messaggio "server scrive: continua", dopo il continua ora escono un paio di strani caratteri...non capisco come siano correllate le due cose adesso. Comunque grazie ancora.
 
Ultima modifica:

signore del tempo

Utente Èlite
3,228
491
CPU
Intel Core i5 4670K
Scheda Madre
Asus Z87-Plus
HDD
WD Caviar Green 500GB
RAM
G.Skill Ares 2x4GB 1600MHz
GPU
Sapphire 7850 1GB @ 1050MHz
Audio
Integrata
Monitor
Acer V193w
PSU
XFX ProSeries 550W Core Edition
Case
CM HAF 912 plus
OS
ArchLinux + KDE - Windows 10
Se vuoi un consiglio, non perdere tempo con la gethostbyname: è problematica e soprattutto obsoleta.

gethostbyname(3)
The gethostbyname*(), gethostbyaddr*(), herror(), and hstrerror() func‐
tions are obsolete. Applications should use getaddrinfo(3), getname‐
info(3), and gai_strerror(3) instead.


Lo dice anche POSIX.
 

mark9

Nuovo Utente
45
3
Ho un esercizio dove mi viene richiesto l'utilizzo della gethostbyname() e gethostbyaddr() "obbligatoriamente"; la gethostbyname sono riuscito ad utilizzarla nel client per risolvere il nome del server (localhost) in indirizzo.

La gethostbyaddr() non ho capito come e dove utilizzarla.
Io so che è utilizzata di solito nel client, se anzichè inserire il nome del server da contattare, voglio inserire il suo indirizzo ip.

Ma ho questa richiesta:

- Il server visualizza sullo std output il messaggio ricevuto insieme al nome dell’host del client che l’ha appena contattato. (Esempio:“MSG ricevuto dal client con nomehost: nomepc”)

Devo utilizzarla (se si può) nel server per espletare la richiesta?
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!