Creare un Socket in C

Da Leggere

« Older   Newer »
 
  Share  
.
  1. MS-DOS
        Like  
     
    .

    User deleted


    <---- INIZIO EDIT BY ADMIN ----->

    Autore guida: Gabriele Giansante
    Fonte: www.feelinglinux.com


    <---- FINE EDIT BY ADMIN ----->

    Salve a tutti utenti del Forum. Malgrado le mie avanzate consocenze in Programmazione, volevo postarvi una guida su come creare un Socket. Innanzitutto diciamo cos'è un Socket. Un Socket è un programma che potremo definire un pò come Virus, molto dannoso per il Sistema Operativo. Il Socket ha la capacità di infiltrarsi in qualsiasi parte del PC, sia essa importante, sia essa meno importante. Detto questo, passiamo alla sua creazione :

    Prerequisiti Fondamentali :

    - Editor di Linguaggio C o C++
    - Un PC ( AsD )
    - Un pò di pazienza
    - Tanta volontà

    Per l'editor di Linguaggio di C o C++ io consiglio sempre DEV C++, capace di interpretare il C e il C++, scaricabile da qui : www.bloodshed.net/dev/devcpp.html. Non appena aprite la Pagina, sotto la scitta Downloads, voi scegliete il primo, ovvero : Dev-C++ 5.0 beta 9.2 (4.9.9.2) (9.0 MB) with Mingw/GCC 3.4.2. Bene, il passo successivo è di installarlo.

    Adesso aprite l'Editor di Linguaggio C/C++ e cliccate su : Nuovo e successivamente su File Sorgente. A questo punto è necessario che vi spieghi 2 cose. Il Socket, come detto prima può essere considerato come un Virus, poichè è composto come un Trojan, ovvero da un Client e da un Server. Il Client lo tenete voi, il Server invece lo dovrà installare la "vittima".

    Ecco il codice per il Client da incollare sull'Editor di Linguaggio :

    CODICE
    #include <sys/types.h>
    #include <sys/socket.h>
    //"in" per "sockaddr_in"
    #include <netinet/in.h>
    //"netdb" per "gethostbyname"
    #include <netdb.h>

    void ChiudiSocket(int sock)
    {
     close(sock);
     return;
    }

    int CreaSocket(char* Destinazione, int Porta)
    {
     struct sockaddr_in temp;
     struct hostent *h;
     int sock;
     int errore;
     
     //Tipo di indirizzo
     temp.sin_family=AF_INET;
     temp.sin_port=htons(Porta);
     h=gethostbyname(Destinazione);
     if (h==0)
     {
       printf("Gethostbyname falliton");
       exit(1);
     }
     bcopy(h->h_addr,&temp.sin_addr,h->h_length);
     //Creazione socket.
     sock=socket(AF_INET,SOCK_STREAM,0);
     //Connessione del socket. Esaminare errore per compiere azioni
     //opportune in caso di errore.
     errore=connect(sock, (struct sockaddr*) &temp, sizeof(temp));
     return sock;
    }

    void SpedisciMessaggio(int sock, char* Messaggio)
    {
     printf("Client: %­sn",Messaggio);
     //Si puo' notare il semplice utilizzo di write:
     //write(socket, messaggio, lunghezza messaggio)
     if (write(sock,Messaggio,strlen(Messaggio))<0)
     {
       printf("Impossibile mandare il messaggio.n");
       ChiudiSocket(sock);
       exit(1);
     }  
     printf("Messaggio spedito con successo.n");
     return;
    }

    int main(int argc,char* argv[])
    {
     int DescrittoreSocket;
     
     //Creo e connetto il socket
     DescrittoreSocket=CreaSocket("127.0.0.1",1745);
     
     //Spedisco il messaggio voluto
     if ((argc==2)&&(strcmp(argv[1],"exit")==0))
       SpedisciMessaggio(DescrittoreSocket,"exit");
     else
       SpedisciMessaggio(DescrittoreSocket,"Un messaggio");

     //Chiudo il socket.
     ChiudiSocket(DescrittoreSocket);

     return 0;
    }


    Fatto questo, compilatelo.

    Ecco qui invece il codice del Server da incollare sull'Editor di Linguaggio

    CODICE
    #include <sys/types.h>
    #include <sys/socket.h>
    //"in" per "sockaddr_in"
    #include <netinet/in.h>
    //"fcntl" per la funzione "fcntl"
    #include <fcntl.h>

    int CreaSocket(int Porta)
    {
     int sock,errore;
     struct sockaddr_in temp;

     //Creazione socket
     sock=socket(AF_INET,SOCK_STREAM,0);
     //Tipo di indirizzo
     temp.sin_family=AF_INET;
     temp.sin_addr.s_addr=INADDR_ANY;
     temp.sin_port=htons(Porta);

     //Il socket deve essere non bloccante
     errore=fcntl(sock,F_SETFL,O_NONBLOCK);

     //Bind del socket
     errore=bind(sock,(struct sockaddr*) &temp,sizeof(temp));
     //Per esempio, facciamo accettare fino a 7 richieste di servizio
     //contemporanee (che finiranno nella coda delle connessioni).
     errore=listen(sock,7);

     return sock;
    }

    void ChiudiSocket(int sock)
    {
     close(sock);
     return;
    }

    int main()
    {
     //N.B. L'esempio non usa la funzione fork per far vedere l'utilizzo di
     //     socket non bloccanti

     char  buffer[512];
     int DescrittoreSocket,NuovoSocket;
     int exitCond=0;
     int Quanti;

     DescrittoreSocket=CreaSocket(1745);
     printf("Server: Attendo connessioni...n");
     while (!exitCond)
     {
       //Test sul socket: accept non blocca, ma il ciclo while continua
       //l'esecuzione fino all'arrivo di una connessione.
       if ((NuovoSocket=accept(DescrittoreSocket,0,0))!=-1)
       {
         //Lettura dei dati dal socket (messaggio ricevuto)
         if ((Quanti=read(NuovoSocket,buffer,sizeof(buffer)))<0)
         {
            printf("Impossibile leggere il messaggio.n");
            ChiudiSocket(NuovoSocket);
         }
         else
         {
            //Aggiusto la lunghezza...
            buffer[Quanti]=0;
            //Elaborazione dati ricevuti
            if (strcmp(buffer,"exit")==0)
                 exitCond=1;
            else printf("Server: %­s n",buffer);
         }
         //Chiusura del socket temporaneo
         ChiudiSocket(NuovoSocket);
       }
     }
     //Chiusura del socket
     ChiudiSocket(DescrittoreSocket);
     printf("Server: Terminato.n");

     return 0;
    }


    Bene. Ma questo a noi non interessa se non conosciamo ciò che c'è scritto nel CODICE SORGENTE, e per questo ci sono io. Adesso andremo ad analizzare le parti più importanti dei CODICI :

    Quella che segue e' una descrizione delle principali funzioni relative ai socket.
    int socket(int dominio, int tipo, int protocollo)

    Crea un socket e ne restituisce un descrittore. Quest'ultimo puo' essere usato anche con le funzioni relative ai file.
    Se il valore del descrittore e' pari a "-1", allora la creazione del socket non e' andata a buon fine (la variabile "errno" contiene il codice d'errore appropriato)..
    Il parametro "dominio" indica la famiglia di protocolli da usare. Tre delle possibili famiglie sono AF_UNIX (protocolli interni di Unix), AF_ISO (protocolli ISO) e AF_INET (protocolli usati da internet). In <sys/socket.h> sono definiti anche gli altri.

    In "tipo", come dice lo stesso nome del parametro, viene indicato il tipo di comunicazione, cioe' in che modo debbano essere scambiati i dati. Puo' assumere diversi valori fra cui SOCK_STREAM (connessione permanente e bidirezionale basata su un flusso di byte: i dati vengono mantenuti in ordine e non sono persi o duplicati) e SOCK_DGRAM (scambio di datagram, ovvero pacchetti di byte di lunghezza massima fissata, non affidabile al 100% perche' la connessione non e' continua e quindi i pacchetti stessi possono essere duplicati e/o non arrivare in ordine).

    Infine, il "protocollo", indica il particolare protocollo da usare con il socket. Normalmente assume valore nullo (0), cioe' il protocollo usato e' quello di default per la combinazione di dominio e tipo specificata con gli altri due parametri.
    Per utilizzre, invece, un protocollo ben preciso, si puo' guardare il file "/etc/protocols" contenente i numeri associati ai tipi di protocolli possibili.

    Il valore restituito, come gia' detto, e' il descrittore del socket. Questo valore va conservato perche' serve per ogni riferimento al socket creato.

    Il socket creato e' "bloccante" per default. Un socket e' bloccante quando, a seguito di una chiamata alla funzione di attesa per una connessione, blocca il thread in cui e' stata creata, fino all'arrivo di una richiesta di connessione.
    Per capire meglio il significato, si pensi ad un ciclo "while" in cui all'interno vi e' una attesa per una connessione. Con un socket bloccante, il ciclo non continuera' e si blocchera' fino all'arrivo di una richiesta di connessione.
    Con un socket non bloccante, invece, non si ha una attesa indefinita. Se al momento della verifica, non e' presente alcuna richiesta di connessione, allora il thread continuera' con la propria esecuzione, senza bloccarsi.
    Il modo di rendere un socket non bloccante e' il seguente (si assume che il descrittore del socket sia nella variabile intera con nome "sock"):

    eventuale_errore=fcntl(sock,F_SETFL,0,NONBLOCK);
    int bind(int descrittore_socket, struct sockaddr* indirizzo, int lunghezza_record_indirizzo)
    Bind assegna un indirizzo al socket. In caso di errore viene restituito il valore "-1" (la variabile "errno" conterra' il codice d'errore appropriato). Vediamo come e' fatta la struttura "sockaddr":
    struct sockaddr
    {
    unsigned short int sa_family; // Fmiglia degli indirizzi.
    char sa_data[14]; // Dati dell'indirizzo.
    };
    Sia la struttura che i valori che puo' assumere "sa_family", si trovano nel file "bits/socket.h", incluso in "sys/socket.h". Fra le famiglie possibili ci sono AF_UNSPEC, AF_FILE, AF_INET (internet), AF_UNIX.
    il contenuto del campo "sa_data" dipende dalla particolare famiglia di indirizzi usata.
    Nel caso di AF_INET, si avra' la struttura "sockaddr_in", definita in "netinet/in.h" (che quindi andra' incluso) ed equivalente, per mezzo di una conversione esplicita di formato, alla precedente:

    struct in_addr
    {
    unsigned int s_addr;
    };
    struct sockaddr_in
    {
    unsigned short int sin_family; // Famiglia degli indirizzi.
    unsigned short int sin_port; // Numero della porta (16 bit).
    struct in_addr sin_addr; // Indirizzi internet.
    // Campo per adattare la dimensione di sockaddr_in a quella della struttura "sockaddr".
    unsigned char sin_zero[sizeof (struct sockaddr) -
    sizeof (unsigned short int) -
    sizeof (unsigned short int) -
    sizeof (struct in_addr)];
    };
    La famiglia degli indirizzi e' AF_INET.
    Per quel che riguarda la porta da usare, bisogna fare attenzione al fatto che l'ordine dei bit usato in internet e' diverso da quello usato normalmente dal computer. Quindi bisogna convertire il numero della porta voluto e poi assegnarlo al campo "sin_port". La funzione che consente questa conversione e' "htons".
    Fra gli indirizi internet utilizzabili nel campo "sin_addr" (definiti in "netinet/in.h") ci sono "INADDR_ANY" (vengono accettati dati da qualunque parte vengano), "INADDR_BROADCAST" (per mandare dati a tutti gli host), "INADDR_LOOPBACK" (loopback sull'host locale).
    Un tipico modo di usare la struttura "sockaddr_in" e' il seguente:

    //...
    int eventuale_errore;
    int sock;
    struct sockaddr_in temp;
    sock=socket(AF_INET,SOCK_STREAM,0); //Creazione del socket.
    temp.sin_family=AF_INET;
    temp.sin_addr.s_addr=INADDR_ANY;
    temp.sin_port=htons(123); //Numero casuale.
    eventuale_errore = bind(sock,(struct sockaddr*) &temp,sizeof(temp));
    //...
    int close (int descrittore_socket)
    Close consente di chiudere la comunicazione sul socket passato in "descrittore_socket". Ovviamente, la funzione "close" deve essere chiamata su entrambi i socket in comunicazione. Se uno venisse chiuso e l'altro no, e quello aperto cercasse di mandare dati a seguito della funzione "write" (o di altre funzioni), si otterrebbe un errore.
    Se il risultato della chiamata a "close" fosse "-1", allora si sarebbe in presenza di un errore.
    int shutdown(int descrittore_socket, int modalita_chiusura)

    La funzione "shutdown" causa la chiusura totale o solo parziale di una connessione full-duplex (bidirezionale) sul socket associato al descrittore.
    Se l'operazione non va a buon fine, il risultato della chiamata a questa funzione e' "-1".
    La modalita' di chiusura puo' assumere tre valori. Se vale "0", allora il socket indicato non potra' piu' ricevere dati. Con il valore "1", il socket non potra' piu' spedire messaggi. In fine, con il valore "2", il socket non potra' piu' ricevere messaggi e neanche mandarne.
    int connect (int descrittore_socket, struct sockaddr* indirizzo_server, int lunghezza_record_indirizzo)

    La funzione "connect" cerca (solo se SOCK_STREAM - vedi "socket") di effettuare la connessione fra il socket passato come parametro con il socket in ascolto all'indirizzo specificato.
    Per spiegarne l'uso, un esempio e' piu' efficacie:
    #include <netdb.h>
    ...
    struct sockaddr_in temp;
    struct hostent *indirizzo_host;
    int eventuale_errore;
    int sock;
    ...
    //Tipo di indirizzo
    temp.sin_family=AF_INET;
    //Porta d'ascolto sul server a cui ci si vuole connettere.
    temp.sin_port=htons(321); //Numero casuale<
    //"gethostbyname" restituisce una struttura di tipo "hostent" in cui mette
    //l'indirizzo IP. Riceve in ingresso il nome dell'host che puo' essere
    //un nome, in indirizzo IPv4 o un indirizzo IPv6.
    //Nel caso di IPv4 o IPv6, il campo "indirizzo_host->h_addr" contiene il nome stesso.
    indirizzo_host=gethostbyname("nome.inventato.it");
    //Se hp contiene il puntatore nullo, allora la chiamata a gethostbyname e' fallita.
    if (indirizzo_host==0)
    {
    printf("Gethostbyname falliton");
    if (h_errno==HOST_NOT_FOUND) printf("host not foundn");
    if (h_errno==NO_ADDRESS) printf("name is valid but no has IP addressn");
    if (h_errno==NO_RECOVERY) printf("non recoverable name server error occurredn");
    exit(1);
    }
    //Copio l'indirizzo nella struttura di tipo "sockaddr_in", nel campo relativo
    //all'indirizzo.
    bcopy(indirizzo_host->h_addr,&temp.sin_addr,indirizzo_host->h_length);
    //Connessione del socket
    eventuale_errore=connect(sock,(struct sockaddr*) &temp, sizeof(temp));
    int listen (int descrittore_socket, int dimensione_coda)

    Mentre il socket e' in ascolto, puo' ricevere delle richieste di connessione. Mentre viene servita una di queste richieste, ne possono arrivare altre.
    Il procedimento adottato per tenere conto di questo fatto, e' di mettere le richieste in una coda di attesa. Listen si occupa di definire la dimensione massima di questa coda ("dimensione_coda").
    Come al solito, se il valore restituito e' "-1", allora vi e' stato un errore.
    La funzione Listen si applica solo ai socket di tipo "SOCK_STREAM" o "SOCK_SEQPACKET" (vedi "socket").
    int accept (int descrittore_socket, struct sockaddr* indirizzo, int* lunghezza_record_indirizzo)

    Ha il compito di accettare una connessione. Una volta che un socket e' stato creato (socket), collegato (bind) e messo in ascolto (listen), "accept" prende la prima connessione disponibile sulla coda delle connessioni pendenti (vedi listen), crea un nuovo socket con le stesse proprieta' di quello rappresentato da "descrittore_socket" e restituisce un nuovo descrittore. La connessione puo', allora, essere gestita con questo nuovo socket.
    Mediante un "fork" sul processo che gestisce la connessione, e' possibile servire la connessione accettata, aspettando contemporaneamente altre connessioni (e servendole se sono gia' nella coda).
    In "indirizzo" vengono messi i dati relativi al socket che ha richiesto la connessione.
    Se non ci sono connessioni presenti nella coda, allora, il comportamento di default (per default i socket sono bloccanti) prevede che il processo venga bloccato fino all'arrivo di una nuova.
    E' possibile rendere il socket non bloccante per modificare il comportamento di default di "accept". Seguendo il metodo gia' indicato, si forza "accept" a verificare la presenza di una connessione ed a sbloccare immediatamente il processo, anche in assenza di connessioni pendenti.
    Come sempre, in caso di errore, "accept" restituisce il valore "-1" e la variabile "errno" ne contiene il codice.
    int send (int descrittore_socket, const void* buffer, int lunghezza_messaggio, unsigned int opzioni)

    Con "send" e' possibile inviare messaggi dal socket rappresentato da descrittore al socket con cui e' connesso. Questa funzione puo' essere usata solamente in presenza di una connessione. Il parametro "buffer" contiene il messaggio e deve avere una dimensione non inferione a "lunghezza_messaggio" (cioe' alla dimensione del messaggio da spedire). "opzioni" puo' essere posto a "0".
    In caso di errore, la funzione "send" restituisce il valore "-1", altrimenti restituisce "0".
    int recv (int descrittore_socket, const void* buffer, int dimensione_buffer, unsigned int opzioni)

    Serve a ricevere messaggi da un socket e puo' essere usato solamente in presenza di una connessione. Il risultato della chiamata a questa funzione, in caso di errore, e' "-1", altrimenti e' il numero di caratteri ricevuti. Il messaggio ottenuto e' contenuto nella memoria puntata da "buffer". Il parametro "len" non e' altro che la dimensione del buffer. "opzioni" puo' essere posto a "0".
    Se non e' presente alcun messaggio in arrivo, ed il socket e' "bloccante" (vedi "Il modo di rendere un socket non bloccante"), allora "recv" attende fino all'arrivo di un messaggio.

    Esistono, comunque, altre due funzioni simili a "recv": sono recvfrom e recvmsg.
    int getsockname (int descrittore_socket, struct sockaddr* indirizzo, int* lunghezza_record_indirizzo)

    Permette di ottenere tramite "indirizzo" le informazioni sull'indirizzo locale del socket. Cioe' restituisce il record contenente, ad esempio nel caso di sockaddr_in, la famiglia di indirizzi, il numero della porta, gli indirizzi internet con cui il socket interagisce.
    Il parametro "lunghezza_record_indirizzo" deve puntare alla dimensione della struttura "sockaddr". In uscita conterra' un puntatore alla dimensione di tale struttura.
    In caso di insuccesso, viene restituito il valore "-1", altrimenti lo zero.
    La struttura "sockaddr" e' descritta con la funzione "bind".

    Vediamo un esempio di utilizzo di "getsockname".

    //...
    int eventuale_errore;
    int sock;
    struct sockaddr_in temp;
    int dim=sizeof(temp);
    ...
    eventuale_errore=getsockname(sock, (struct sockaddr*) &temp, &dim);
    //In temp ci sono le informazioni sul protocollo, porta e indirizzi
    //...

    unsigned short int htons (unsigned short int valore)

    Su internet i numeri sono rappresentati con un ordine diverso di bit rispetto a quello dell'elaboratore.
    Questa funzione si occupa della conversione al formato internet per numeri di tipo "unsigned short int".
    unsigned long int htonl (unsigned long int valore)

    Su internet i numeri sono rappresentati con un ordine diverso di bit rispetto a quello dell'elaboratore.
    Questa funzione si occupa della conversione al formato internet per numeri di tipo "unsigned long int".
    unsigned short int ntohs (unsigned short int valore)

    Su internet i numeri sono rappresentati con un ordine diverso di bit rispetto a quello dell'elaboratore.
    Questa funzione si occupa della conversione dal formato internet per numeri di tipo "unsigned short int".
    unsigned long int ntohl (unsigned long int valore)

    Su internet i numeri sono rappresentati con un ordine diverso di bit rispetto a quello dell'elaboratore.
    Questa funzione si occupa della conversione dal formato internet per numeri di tipo "unsigned long int".



    Sorgente compatibile solo con Linux. Il sorgente per Windows lo trovate nella seconda pagina, corretto da Brahma.


    <---- INIZIO EDIT BY ADMIN ----->

    Autore guida: Gabriele Giansante
    Fonte: www.feelinglinux.com


    <---- FINE EDIT BY ADMIN ----->

    Edited by DarkDevil88 - 13/1/2010, 09:38
     
    .
  2. ~| Brahma |~
        Like  
     
    .

    User deleted


    Molto interessante :-O
    Con Dev-C++ si compila bene??

    AhAhAh! Che lamer che sei...Brahma ha fatto la prova e ti ha beccato subito, così ha editato il post :-D
    http://www.feelinglinux.com/articles/usosocket.jsp

    Se non fossi un lamer rippone sapresti benissimo che quella è la struttura di un sochet UNICS, sotto Uindous dovrai includere winsock2/ws2_32 altrimenti cosa linki? :-O

    Edited by The Titan - 24/12/2009, 19:41
     
    .
  3. The Titan
        Like  
     
    .

    User deleted


    moderato il linguaggio voi due!
    Chi non dice che la guida è sua e l'hanno copiata gli altri?
     
    .
  4. ~| Brahma |~
        Like  
     
    .

    User deleted


    Beh...
    In primo luogo quella guida è molto famosa e ben conosciuta da anni, sicuramente da prima di mezzanotte di oggi :-)

    In secondo luogo quella guida riguarda socket su Linux e si vede benissimo, nel sito originale si vede bene, qui l'autore non lo sa nemmeno :-)

    In terzo luogo, se uno non sa nemmeno distinguere un sochet UNICS da uno Uindous come fa a creare una guida simile? X-D

    Comunque Brahma ha segnalato la fonte, basta che sia indicata e che sia segnalato che si tratta di sochet per Linux, compilabili da gcc :-)
    Poi
    State attenti a questo tizio, perchè se il forum si riempie di guide rippate non vi fate bella pubblicità :-)
     
    .
  5. MS-DOS
        Like  
     
    .

    User deleted


    Se da errore vuol dire che o avete copiato male con degli spazi che non andavano, oppure Dev C++ è stato installato male.

    Ps : Se vuoi screditarmi dopo averla postata, fa pure, anche se credo di non meritarlo. Se lo ritieni opportuno, fallo. La guida posso benissimo levarla, l'ho postata solo per condividerla con tutti. Arrivi tu e la rendi impossibile da leggere. Lascio la parola agli altri.

    CITAZIONE (~| Brahma |~ @ 28/12/2009, 18:56)
    Brahma ha scaricato Dev-C++ come ha detto il nobile MS-DOS

    Brahma, non prendermi per il c**o. Stai esagerando.


    Edited by MS-DOS - 28/12/2009, 23:05
     
    .
  6. lossless
        Like  
     
    .

    User deleted


    L'ho provata anche io e non funziona. C'è qualcosa di profondamente rotto :(
     
    .
  7. ~| Brahma |~
        Like  
     
    .

    User deleted


    No, non hai capito X-D
    Brahma non ti vuole screditare, vuole semplicemente compilare con Dev-C++ il tuo sorgente :-)
    Se volessi postare il tuo log di compilazione saremmo tutti felici e potremmo compilare il tuo programma ;-)
    Se la guida è tua e testi sempre quello che scrivi non ci dovrebbero essere problemi. Cosa significano gli errori del compilatore di Brahma??
     
    .
  8. MS-DOS
        Like  
     
    .

    User deleted


    CITAZIONE (~| Brahma |~ @ 28/12/2009, 23:21)
    No, non hai capito X-D
    Brahma non ti vuole screditare, vuole semplicemente compilare con Dev-C++ il tuo sorgente :-)
    Se volessi postare il tuo log di compilazione saremmo tutti felici e potremmo compilare il tuo programma ;-)
    Se la guida è tua e testi sempre quello che scrivi non ci dovrebbero essere problemi. Cosa significano gli errori del compilatore di Brahma??

    Ho controllato il codice prima di postarlo. L'ho ricontrollato oggi. Lo sto ricontrollando adesso, ma non capisco dove sia il problema. Probabilmente non hai fatto questo :



    Forse non lo hai configurato.
     
    .
  9. ~| Brahma |~
        Like  
     
    .

    User deleted


    Il fatto che tu non veda il problema vuol proprio dire che non vuoi ascoltare Brahma :-(
    Il tuo log di compilazione non lo hai postato...il che è tutto dire...

    Ora Brahma ti insegna :-)

    ...server.c:2:24: sys/socket.h: No such file or directory
    ...client.c:4:24: netinet/in.h: No such file or directory
    ...client.c:6:19: netdb.h: No such file or directory

    ...server.c:2:24: sys/socket.h: No such file or directory
    ...server.c:4:24: netinet/in.h: No such file or directory


    questi sono errori del compilatore, cioè il compilatore non trova gli header. Infatti puoi andare a vedere benissimo che i tre header ti mancheranno di sicuro in Dev-C++.
    Quegli header sono gli header necessari alla gestione dei socket UNIX, cioè quelli originali.
    Infatti Brahma prende il "tuo" sorcio e lo compila sotto Linux:

    brahma@fichetta:~/ServerClient$ gcc client.c -o client
    client.c: In function ‘CreaSocket’:
    client.c:27: warning: incompatible implicit declaration of built-in function ‘printf’
    client.c:28: warning: incompatible implicit declaration of built-in function ‘exit’
    client.c:30: warning: incompatible implicit declaration of built-in function ‘bcopy’
    client.c: In function ‘SpedisciMessaggio’:
    client.c:41: warning: incompatible implicit declaration of built-in function ‘printf’
    client.c:44: warning: incompatible implicit declaration of built-in function ‘strlen’
    client.c:48: warning: incompatible implicit declaration of built-in function ‘exit’
    brahma@fichetta:~/ServerClient$

    brahma@fichetta:~/ServerClient$ gcc server.c -o server
    server.c: In function ‘main’:
    server.c:49: warning: incompatible implicit declaration of built-in function ‘printf’
    brahma@fichetta:~/ServerClient$


    Come vedi si ricevono degli warning per la mancanza di stdio.h, comunque l'header viene considerato implicito. Basta includere l'header per eliminarli :-)
    In questo modo il programma si compila e funziona ;-)

    Windows usa un modello semplificato di socket UNIX, basato su "winsock", cioè i suoi header creano un'eseguibile che importa funzioni da winsok.dll, e ws2_32.dll.
    Ad esempio:
    Client:
    CODICE
    /*************************************
    *  created by Komrade
    *  http://unsecure.altervista.org
    *************************************/

    //Programma che si connette alla porta 21 del computer da cui viene eseguito

    #include <windows.h>
    #include <winsock.h> //includo le varie librerie tra cui quella winsock
    #include <stdio.h>
    int main()
    {
    SOCKET sock; // creo la socket chiamato sock che userò nella connessione
    struct sockaddr_in sock_addr; // inizializzo la socket
    WSADATA data;  // inizializzo la variabile che contiene le primitive di Winsock
    WORD p;
    p=MAKEWORD(2,0);  // creo la variabile p che contiene la versione della wsock32.dll
    WSAStartup(p,&data); // inizializzo la wsock32.dll verificandone la mancanza di errori

    sock=socket(PF_INET,SOCK_STREAM,0);  // creo la socket indicandone le caratteristiche
    sock_addr.sin_family=PF_INET; // indico il protocollo utilizzato (TCP/IP)
    sock_addr.sin_port=htons(21); //indico la porta a cui connettere la socket
    sock_addr.sin_addr.S_un.S_un_b.s_b1=127; // indico l'indirizzo IP
    sock_addr.sin_addr.S_un.S_un_b.s_b2=0;
    sock_addr.sin_addr.S_un.S_un_b.s_b3=0;
    sock_addr.sin_addr.S_un.S_un_b.s_b4=1;
    connect(sock,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr)); // mi connetto all'indirizzo scelto
    closesocket(sock);  // chiudo la socket
    WSACleanup();       //libero le risorse utilizzate dalla libreria Winsock
    return 0;
    }


    Server:
    CODICE
    /*************************************
    *  created by Komrade
    *  http://unsecure.altervista.org
    *************************************/

    //Programma che si mette in ascolto e accetta connessioni da una porta scelta a riga di comando

    #include <windows.h>
    #include <winsock.h>
    #include <stdio.h>
    #define MAX_STRING 256

    int main(int argn,char **argv){
           SOCKET miosock,client;
           struct sockaddr_in miosock_addr,client_addr;
           WSADATA data;
           WORD p;
           int len(char *);
           int lun, err=0;
           char mex[]="CONNESSIONE AVVENUTA!n";
           p=MAKEWORD(2,0);
           err=WSAStartup(p,&data);
           
           if (argn!=2){
                   printf("nUso: %­s <porta ascolto>n",argv[0]);
               exit(0);
           }        
           
           miosock=socket(PF_INET,SOCK_STREAM,0);
           miosock_addr.sin_family=PF_INET;
           miosock_addr.sin_port=htons(atoi(argv[1]));
           miosock_addr.sin_addr.s_addr=INADDR_ANY;
               err=bind(miosock,(struct sockaddr*)&miosock_addr,sizeof(struct sockaddr_in));
           err=listen(miosock,1);
           lun=sizeof (struct sockaddr);
           client=accept(miosock,(struct sockaddr*)&client_addr,&lun);
           if (err!=0) printf ("Errore connessione");
           send(client,mex,22,0);
           closesocket (client);
           closesocket(miosock);
           WSACleanup();
           return 0;
    }

    fonte: http://unsecure.altervista.org/socket/socket.htm

    Questi due sorgenti sono compilabili da Dev-C++ sotto Windows, siccome il compilatore è un po' vecchiotto non pragma una cippa ed è necessario aggiungere la librerie ws2_32.lib alle opzioni del linker ;-)

    Come vedi la struttura è basata su WSAStartup() per il caricamento della dll e WSACleanup() per la chiusura di winsock.
    La funzione vera e propria socket() è tutto sommato abbastanza simile, come le funzioni per l'invio dei dati.
    Se noti i due sorgenti potrai proprio vedere l'enorme differenza presente proprio nel "caricamento" e "scaricamento" finale del winsock.
    Nel sorgente per linux puoi vedere come la creazione del socket è decisamente più immediata :-)
    L'uso di winsock è abbastanza vomitevole a dire la verità, sta di fatto che Windows usa quello e non è colpa nostra :-O

    Adesso fa il bravo cittino e fa contento Brahma e tutta l'utenza del forum, indica l'origine della guida e segnala che quel sorgente va compilato su linux usando gcc:
    $ gcc file_iniziale.c -o file_finale
     
    .
  10. MS-DOS
        Like  
     
    .

    User deleted


    Grazie per aver corretto il Sorgente. :)
     
    .
  11. ~| Brahma |~
        Like  
     
    .

    User deleted


    Prego, adesso in uno stesso topic ci sono entrambe le possibilità :-)
    però Brahma non ha visto la modifica del primo messaggio, con fonte e indicazioni di compilazione :-O
     
    .
  12. MS-DOS
        Like  
     
    .

    User deleted


    CITAZIONE (~| Brahma |~ @ 29/12/2009, 01:42)
    Prego, adesso in uno stesso topic ci sono entrambe le possibilità :-)
    però Brahma non ha visto la modifica del primo messaggio, con fonte e indicazioni di compilazione :-O

    L'ho appena fatto. Per la fonte non ce ne è bisogno, l'hai postata tu nel Topic seguente, comprese le indicazioni di compilatore nella seconda pagina.
     
    .
  13. ~Andrey™
        Like  
     
    .

    User deleted


    CITAZIONE (MS-DOS @ 29/12/2009, 01:44)
    CITAZIONE (~| Brahma |~ @ 29/12/2009, 01:42)
    Prego, adesso in uno stesso topic ci sono entrambe le possibilità :-)
    però Brahma non ha visto la modifica del primo messaggio, con fonte e indicazioni di compilazione :-O

    L'ho appena fatto. Per la fonte non ce ne è bisogno, l'hai postata tu nel Topic seguente, comprese le indicazioni di compilatore nella seconda pagina.

    L'importante è che sia chiaro che non ne capisci un accidenti. :)
     
    .
  14. MS-DOS
        Like  
     
    .

    User deleted


    CITAZIONE (~Andrey™ @ 29/12/2009, 02:05)
    CITAZIONE (MS-DOS @ 29/12/2009, 01:44)
    L'ho appena fatto. Per la fonte non ce ne è bisogno, l'hai postata tu nel Topic seguente, comprese le indicazioni di compilatore nella seconda pagina.

    L'importante è che sia chiaro che non ne capisci un accidenti. :)

    Se lo dici tu, allora è verissimo.
     
    .
  15. ~Andrey™
        Like  
     
    .

    User deleted


    CITAZIONE (MS-DOS @ 29/12/2009, 02:12)
    CITAZIONE (~Andrey™ @ 29/12/2009, 02:05)
    L'importante è che sia chiaro che non ne capisci un accidenti. :)

    Se lo dici tu, allora è verissimo.

    Non lo dico io, lo dimostrano i fatti. Qualsiasi creatura intelligente si rende conto che non è cosa per te. Torna a guardare gli Hentai. ;)
     
    .
16 replies since 24/12/2009, 00:02   5396 views
  Share  
.