Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Problemi con le socket di Berkeley
Forum - C/C++ - Problemi con le socket di Berkeley

Avatar
salvo1988 (Normal User)
Newbie


Messaggi: 2
Iscritto: 30/04/2011

Segnala al moderatore
Postato alle 15:44
Martedì, 03/05/2011
Ciao,
Sto cercando di creare una semplice chat in c usando le socket di Berkeley.Le richieste di progetto del programma sono le seguenti:
Realizzare una chat. Un server contiene una lista dei client che si sono connessi. Il client si connette al server per chiedere una lista degli altri client con cui potersi connettere ma resta anche in attesa di connessioni di altri client (queste connessioni saranno comunicazioni di chat).

Il programma è praticamente pronto ed è stato realizzato in modo che un client apre una connessione UDP con il server,  il quale per ogni nuovo utente aggiorna una lista dei client connessi e per ciascuno di questi client prende informazioni sulla porta TCP sulla quale questi restano in attesa di nuove richieste di connessioni da parte di altri client.Una volta connesso al server il client può richiedere la lista degli utenti connessi al server e connettersi con uno di questi  aprendo una sessione di chat privata(creando quindi una socket che usa la porta TCP diversa rispetto a quella con cui è connesso al server che invece usa l'UDP) in cui lo scambio di messaggi tra i due utenti avviene senza passare dal server(per cui ciascun client può anche funzionare da server).A questo punto si apre un canale diretto tra i due utenti i quali senza problemi possono procedere allo scambio di messaggi.
Il problema che nasce è invece il seguente:
nel momento in cui il client che ha aperto la sessione di chat privata decide di chiudere la connessione tutto funziona correttamente, viceversa se è il client che ha accettato la richiesta di sessione di chat(cioè se il client sta funzionando da server)a chiudere la connessione tra i due il programma crasha.

Non riesco a capire a cosa può essere dovuto e quindi non riesco neanche a risolverlo.  :-?:-?
Di seguito inserisco il codice(prima il client e poi il server)vi prego aiutatemi a trovare il problema.


Codice sorgente - presumibilmente C++

  1. #include <arpa/inet.h>
  2. #include <netinet/in.h>
  3. #include <pthread.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/socket.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10.  
  11. #define BUFLEN 512
  12. #define PORT 9930
  13. #define SRV_IP "127.0.0.1"
  14.  
  15. /* ciclo principale del programma = true */
  16. int ciclo = 1;
  17.  
  18. /*
  19.  * parametri di configurazione della socket in ascolto di altri client
  20.  * rispettivamente descrittore della socket e porta.
  21.  * se la porta è occupata viene incrementata prima di riprovare
  22.  * questo è necessario per mettere in ascolto due client entrambi su localhost
  23.  */
  24. int connected_ts = 0;
  25. int ts_port = 9930;
  26.  
  27. /*
  28.  * parametri di configurazione della socket in uscita verso un altro client
  29.  * per connettersi ogni client deve prima chiedere al server quali client sono disponibili
  30.  * e i loro ip:porta
  31.  */
  32. int connected_tc = 0;
  33.  
  34. /*
  35.  * il nick che inviamo al server viene mantenuto qui
  36.  */
  37. char * nick;
  38.  
  39. /*
  40.  * substring workaround per C
  41.  */
  42. char * substring(const char* str, size_t begin, size_t len) {
  43.     if (str == 0 || strlen(str) == 0 || strlen(str) < begin || strlen(str) < (begin+len))
  44.         return "";
  45.     return strndup(str + begin, len);
  46. }
  47.  
  48. /*
  49.  * come detto ogni client ha una socket aperta in ascolto di altri client
  50.  * la socket viene aperta in un thread e resta aperta per tutto il ciclo di vita del client
  51.  */
  52. void * thread_server(void *x) {
  53.     int sock, bytes_recieved, i = 1;
  54.     char s_buffer[BUFLEN], r_buffer[BUFLEN];
  55.  
  56.     struct sockaddr_in server_addr, client_addr;
  57.     int sin_size = sizeof(struct sockaddr_in);
  58.  
  59.     if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  60.         printf("Socket\n");
  61.         exit(-1);
  62.     }
  63.  
  64.     if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int)) == -1) {
  65.         printf("Setsockopt\n");
  66.         exit(-1);
  67.     }
  68.  
  69.     memset((void *)&server_addr, 0, sizeof(server_addr));
  70.     server_addr.sin_family = AF_INET;
  71.     server_addr.sin_addr.s_addr = INADDR_ANY;
  72.  
  73.     do {
  74.         ts_port++;
  75.         server_addr.sin_port = htons(ts_port);
  76.         i = bind(sock, (struct sockaddr *) & server_addr, sizeof(struct sockaddr));
  77.     } while(i == -1 && ts_port <= 10930);
  78.  
  79.     if(i == -1) {
  80.         printf("Unable to bind\n");
  81.         exit(-1);
  82.     }
  83.  
  84.     if(listen(sock, 5) == -1) {
  85.         printf("Listen\n");
  86.         exit(-1);
  87.     }
  88.  
  89.     connected_ts = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
  90.  
  91.     printf("I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  92.  
  93.     while(1) {
  94.         memset(r_buffer,'\0',BUFLEN);
  95.         bytes_recieved = recv(connected_ts,r_buffer,BUFLEN,0);
  96.         if(strcmp(r_buffer , "DISCONNECT") == 0) {
  97.             printf("I got a disconnect request from (%s , %d) ************** Disconnection performed\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  98.             break;
  99.         } else {
  100.             printf("%s: %s\n" , nick, r_buffer);
  101.         }
  102.     }
  103.     close(sock);
  104.     sock = 0;
  105.     connected_ts = 0;
  106. }
  107.  
  108. /*
  109.  * la socket verso un altro client viene aperta nel main,
  110.  * successivamente viene creato il thread che cicla sulla lettura di questa socket
  111.  */
  112. void * thread_client(void *x) {
  113.     int bytes_recieved;
  114.     char s_buffer[BUFLEN], r_buffer[BUFLEN];
  115.     while(1) {
  116.         memset(r_buffer,'\0',BUFLEN);
  117.         bytes_recieved=recv(connected_tc, r_buffer, BUFLEN,0);
  118.         if(strcmp(r_buffer, "DISCONNECT") == 0) {
  119.             printf("Disconnecting from remote host\n");
  120.             break;
  121.         } else {
  122.             printf("%s: %s\n" , nick, r_buffer);
  123.         }
  124.     }
  125.     close(connected_tc);
  126.     connected_tc = 0;
  127. }
  128.  
  129.  
  130. int main(void) {
  131.     /* i thread client/server */
  132.     pthread_t p_thread_server;
  133.     pthread_t p_thread_client;
  134.  
  135.     /* i parametri di connessione verso il server centrale */
  136.     struct sockaddr_in server_socket;
  137.     int s, i, server_lenght = sizeof(server_socket);
  138.     char buf[BUFLEN];
  139.  
  140.     /* creo la socket in ascolto di altri client */
  141.     if(pthread_create(&p_thread_server, NULL, thread_server, NULL) != 0) {
  142.         fprintf(stderr, "errore non posso creare il thread 1\n");
  143.         exit(-1);
  144.     }
  145.  
  146.     if((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
  147.       printf("socket");
  148.       exit(-1);
  149.     }
  150.  
  151.     /* imposto i parametri di connessione al server centrale */
  152.     memset((void *)&server_socket, 0, sizeof(server_socket));
  153.     server_socket.sin_family = AF_INET;
  154.     server_socket.sin_port = htons(PORT);
  155.  
  156.     if(inet_aton(SRV_IP, &server_socket.sin_addr)==0) {
  157.       fprintf(stderr, "inet_aton() failed\n");
  158.       exit(-1);
  159.     }
  160.     printf("****************************************************************************\n");
  161.     printf("****************************************************************************\n");
  162.     printf("****************************************************************************\n");
  163.     printf("****                                                                    ****\n");
  164.     printf("****                                                                    ****\n");
  165.     printf("****          ********* ****    ****   ********   ************          **** \n");
  166.     printf("****          ********* ****    ****  **********  ************          **** \n");
  167.     printf("****          ****      ************ ****    ****     ****              ****\n");
  168.     printf("****          ****      ************ ************     ****              ****\n");
  169.     printf("****          ********* ****    **** ****    ****     ****              ****\n");
  170.     printf("****          ********* ****    **** ****    ****     ****              ****\n");
  171.     printf("****                                                                    ****\n");
  172.     printf("****                                                                    ****\n");
  173.     printf("****************************************************************************\n");
  174.     printf("****************************************************************************\n");
  175.     printf("****************************************************************************\n");
  176.     printf("Digita il comando NAME|<nick utente> per inserire il tuo nickname\n");
  177.     printf("Digita il comando exit per uscire\n");
  178.     printf("Digita il comando LISTA per richiedere la lista dei client connessi al server\n");
  179.     printf("Digita il comando CONNECT|<nick utente> per aprire una sessione di chat con <nick utente>\n");
  180.     printf("Digita il comando DISCONNECT per chiudere la sessione di chat\n");
  181.     /* while 1 il programma resta connesso al server centrale */
  182.     while(ciclo) {
  183.         /*
  184.          * svuoto completamente il buffer prima di ogni lettura
  185.          * questo serve per evitare di leggere vecchie stringhe concatenate a quella corrente
  186.          */
  187.         memset(buf,'\0',BUFLEN);
  188.  
  189.         /* leggo da standard in nel buffer */
  190.         scanf("%s", buf);
  191.  
  192.         /*
  193.          * se siamo connessi a un altro client come client
  194.          * sto chattando direttamente con qualcuno,
  195.          * invio i messaggi a lui.
  196.          */
  197.         if(connected_tc > 0) {
  198.             if(send(connected_tc, buf, BUFLEN, 0) == -1) {
  199.                 printf("send()");
  200.             }
  201.             if(strcmp(buf, "DISCONNECT") == 0) {
  202.                 close(connected_tc);
  203.                 connected_tc = 0;
  204.             }
  205.         } else
  206.         /*
  207.          * se siamo connessi a un altro client come server
  208.          * sto chattando direttamente con qualcuno,
  209.          * invio i messaggi a lui.
  210.          */
  211.         if(connected_ts > 0) {
  212.             if(strcmp(buf, "exit") == 0) {
  213.                 if(send(connected_ts, buf, BUFLEN, 0) == -1) {
  214.                     printf("send()");
  215.                 }
  216.                 close(connected_ts);
  217.                 connected_ts = 0;
  218.             } else {
  219.                 char res[BUFLEN];
  220.                 if(send(connected_ts, buf, BUFLEN, 0) == -1) {
  221.                     printf("send()");
  222.                 }
  223.             }
  224.         } else
  225.         /*
  226.          * se non siamo connessi direttamente a nessuno client
  227.          * invio i messaggi al server centrale.
  228.          * in assenza di messaggi validi il server centrale agisce come un echo server.
  229.          * i comandi validi sono:
  230.          * 'exit' -> chiude il programma
  231.          * 'DELETE' -> rimuove il client dalla lista dei client noti contenuta nel server centrale, digitando exit questo comando viene inviato automaticamente
  232.          * 'NAME|xxxx' -> inserisce il client nella lista dei client conosciuti contenuta nel server centrale e setta il nick del client a xxxx, per cambiare nick digitare di nuovo il comando
  233.          * 'TCP|xx' -> invia al server centrale la porta su cui il client è in ascolto di connessioni dirette, questo comando viene inviato automaticamente dopo il comando NAME
  234.          * 'LISTA' -> ottiene dal server centrale la lista dei client conosciuti
  235.          * 'CONNECT|xxxx' -> chiede al server centrale ip e porta del client con nick xxxx e esegue la connessione diretta, quindi fa partire il thread di lettura della socket client
  236.          * 'DEBUG' -> fa stampare al server informazioni utili non inviate al client
  237.          */
  238.         {
  239.             if(strcmp(buf, "exit") == 0) {
  240.                 /* in caso di uscita setto ciclo a 0 e invio 'DELETE' */
  241.                 ciclo = 0;
  242.                 if(sendto(s, "DELETE", 6, 0, (struct sockaddr *) &server_socket, server_lenght) == -1) {
  243.                     printf("sendto()");
  244.                 }
  245.             } else if(strcmp("NAME|", substring(buf, 0, 5)) == 0) {
  246.                 /* salvo il nick nella variabile all'inizio e lo invio al server centrale per essere inserito nella lista */
  247.                 nick = substring(buf, 5, strlen(buf) - 5);
  248.                 if(sendto(s, buf, BUFLEN, 0, (struct sockaddr *) &server_socket, server_lenght) == -1) {
  249.                     printf("sendto()");
  250.                 }
  251.             } else {
  252.                 /* invio al server centrale tutto quello che leggo */
  253.                 if(sendto(s, buf, BUFLEN, 0, (struct sockaddr *) &server_socket, server_lenght) == -1) {
  254.                     printf("sendto()");
  255.                 }
  256.             }
  257.             /*
  258.              * dopo l'invio al server centrale di qualcosa aspetto che il server mi risponde, il server agisce come un echo server, sia in caso di comandi validi che di comandi non validi, quindi ci sarà sempre un ritorno */
  259.             if(recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &server_socket, &server_lenght) == -1) {
  260.                 printf("recvfrom()");
  261.             }
  262.             if(strcmp(buf, "PROVIDE_TCP_PORT") == 0) {
  263.                 /* 'PROVIDE_TCP_PORT' -> il server vuole conoscere la porta su cui stiamo aspettando i client diretti, questo comando arriva automaticamente dopo l'invio di 'NAME' e rispondiamo quindi automaticamente col comando 'TCP' */
  264.                 sprintf(buf,"TCP|%d",ts_port);
  265.                 if(sendto(s, buf, BUFLEN, 0, (struct sockaddr *) &server_socket, server_lenght) == -1) {
  266.                     printf("sendto()");
  267.                 }
  268.                 if(recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &server_socket, &server_lenght) == -1) {
  269.                     printf("recvfrom()");
  270.                 }
  271.             } else if(strcmp("CLIENT|", substring(buf, 0, 7)) == 0) {
  272.                 /* 'CLIENT|xxxx|yy' -> il server ci comunica ip e porta del client con cui abbiamo scelto di connetterci, dopo vari split avvio la socket diretta verso il client che farà da server nella connessione diretta */
  273.                 char * info = substring(buf, 7, strlen(buf) - 7);
  274.                 char * _info = strstr(info, "|");
  275.                 int pos = _info - info;
  276.                 char * ip = substring(info, 0, pos);
  277.                 int porta = atoi(substring(info, pos + 1, strlen(info) - pos - 1));
  278.                 printf("CONNECTING TO %s PORT %d\t", ip, porta);
  279.         printf("* ");
  280.         printf("* ");
  281.         printf("* ");
  282.         printf("* ");
  283.         printf("* ");
  284.         printf("* ");
  285.         printf("* ");
  286.         printf("* ");
  287.         printf("* ");
  288.         printf("*\t");
  289.         struct sockaddr_in server_addr;
  290.  
  291.                 if ((connected_tc = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  292.                     printf("Socket");
  293.                     break;
  294.                 }
  295.  
  296.                 memset((void *)&server_addr, 0, sizeof(server_addr));
  297.                 server_addr.sin_family = AF_INET;
  298.                 server_addr.sin_port = htons(porta);
  299.                 server_addr.sin_addr.s_addr = inet_addr(ip);
  300.  
  301.                 if(connect(connected_tc, (struct sockaddr *) & server_addr, sizeof(struct sockaddr)) == -1) {
  302.                     printf("Connect");
  303.                     break;
  304.                 }
  305.                 /* se tutto è andato bene apro il thread che cicla sulla socket in lettura */
  306.         printf("CONNECTED\n");
  307.                 if(pthread_create(&p_thread_client, NULL, thread_client, NULL) != 0) {
  308.                     fprintf(stderr, "errore non posso creare il thread 2\n");
  309.  
  310.                 }
  311.             } else {
  312.                 /* questo viene eseguito quando un comando non valido ritorna dal server, può essere eliminato */
  313.                 printf("> %s\n", buf);
  314.             }
  315.         }
  316.         fflush(stdout);
  317.     }
  318.  
  319.     close(s);
  320.     return 0;
  321. }



Codice sorgente - presumibilmente C++

  1. #include <arpa/inet.h>
  2. #include <netinet/in.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9.  
  10. /* true non esiste in c, bisogna definirlo */
  11. #define TRUE 1
  12. #define BUFLEN 512
  13. #define PORT 9930
  14.  
  15. /*
  16.  * substring workaround per C
  17.  */
  18. char * substring(const char* str, size_t begin, size_t len) {
  19.     if (str == 0 || strlen(str) == 0 || strlen(str) < begin || strlen(str) < (begin+len))
  20.         return "";
  21.     return strndup(str + begin, len);
  22. }
  23.  
  24. /* struttura client, contenente:
  25.  * ip -> l'ip da dove proviene il client
  26.  * portaudp -> la porta di connessione server centrale <-> client
  27.  *      la coppia ip:portaudp definisce univocamente un client, è necessario in caso di diversi client su localhost
  28.  * portatcp -> la porta su cui il client aspetta un altro client per la connessione diretta
  29.  * nick -> il nick del client
  30.  */
  31. struct client {
  32.     char * ip;
  33.     int portaudp;
  34.     int portatcp;
  35.     char * nick;
  36.     struct client *next;
  37. };
  38. typedef struct client Tnodo;
  39.  
  40. /* la lista in cui manteniamo i client e la sua dimensione */
  41. Tnodo * lista = NULL;
  42. int lista_size = 0;
  43.  
  44. /* aggiunta di un client alla lista conoscendo ip, porta e nick */
  45. int add_client(char * ip, int portaudp, char * nick) {
  46.     Tnodo * L;
  47.     if(lista == NULL) {
  48.         /* se la lista è vuota creiamo il primo nodo con i dati necessari */
  49.         lista = (Tnodo*) malloc (sizeof(Tnodo));
  50.         lista->ip = ip;
  51.         lista->portaudp = portaudp;
  52.         lista->portatcp = 0;
  53.         lista->nick = nick;
  54.         lista->next = NULL;
  55.         lista_size++;
  56.     } else {
  57.         L = lista;
  58.         while(L != NULL) {
  59.             /* se la lista non è vuota scandiamo i nodi alla ricerca di quello del client */
  60.             if(strcmp(L->ip, ip) == 0 && L->portaudp == portaudp) {
  61.                 /* se viene trovato cambiamo nick al client senza creare un nuovo nodo */
  62.                 L->nick = nick;
  63.                 return 1;
  64.             }
  65.             L = L->next;
  66.         }
  67.         L = lista;
  68.         /* se non viene trovato scandiamo la lista fino all'ultimo nodo e appendiamo in coda un nuovo nodo per il nuovo client */
  69.         while(L->next != NULL) {
  70.             L = L->next;
  71.         }
  72.         L->next = (Tnodo*) malloc (sizeof(Tnodo));
  73.         L->next->ip = ip;
  74.         L->next->portaudp = portaudp;
  75.         L->next->portatcp = 0;
  76.         L->next->nick = nick;
  77.         L->next->next = NULL;
  78.         lista_size++;
  79.     }
  80.     return 1;
  81. }
  82.  
  83. /* dopo aver inserito il client nella lista dobbiamo inserire la porta tcp su cui è in ascolto di altri client */
  84. int set_tcp_port(char * ip, int portaudp, int portatcp) {
  85.     Tnodo * L = lista;
  86.     while(L != NULL) {
  87.         if(strcmp(L->ip, ip) == 0 && L->portaudp == portaudp) {
  88.             L->portatcp = portatcp;
  89.             return 1;
  90.         }
  91.         L = L->next;
  92.     }
  93.     return 0;
  94. }
  95.  
  96. /* dopo il comando 'LISTA' creiamo la lista dei client e la inviamo */
  97. char * get_clients(char * ip, int portaudp) {
  98.     Tnodo * L;
  99.     char *result = NULL;
  100.     int i = 0, len = 0;
  101.  
  102.     /* la prima scansione serve a calcolare lo spazio da allocare alla stringa, per evitare buffer di migliaia di posizioni
  103.      * forse inutili o anche insufficienti */
  104.     L = lista;
  105.     while (L != NULL) {
  106.         if(strcmp(L->ip, ip) != 0 || L->portaudp != portaudp) {
  107.             len += strlen(L->nick) + 1;
  108.         }
  109.         L = L->next;
  110.     }
  111.  
  112.     /* allochiamo lo spazio con malloc */
  113.     result = malloc(len * sizeof(char) + 1);
  114.     if(result == NULL) {
  115.         fprintf(stderr, "Error - mkconcat -> malloc()\n");
  116.         return NULL;
  117.     }
  118.  
  119.     /* con questa seconda scansione inseriamo effettivamente i nick dei client nella lista evitando il nick che ha fatto la richiesta */
  120.     L = lista;
  121.     while (L != NULL) {
  122.         if(strcmp(L->ip, ip) != 0 || L->portaudp != portaudp) {
  123.             if(strcat(result, "\n") == NULL) {
  124.                 fprintf(stderr, "Error - strcat()\n");
  125.                 return NULL;
  126.             }
  127.             if(strcat(result, L->nick) == NULL) {
  128.                 fprintf(stderr, "Error - strcat()\n");
  129.                 return NULL;
  130.             }
  131.         }
  132.         L = L->next;
  133.     }
  134.     return result;
  135. }
  136.  
  137. /* dopo 'CONNECT|nick' recuperiamo ip e porta del client cercato e li inviamo al client che li ha chiesti */
  138. char * get_client(char * nick) {
  139.     Tnodo * L = lista;
  140.     while(L != NULL) {
  141.         if(strcmp(L->nick, nick) == 0) {
  142.             sprintf(nick, "CLIENT|%s|%d", L->ip, L->portatcp);
  143.             return nick;
  144.         }
  145.         L = L->next;
  146.     }
  147.     return "NOT_FOUND";
  148. }
  149.  
  150. /* dopo 'DELETE' troviamo il client e lo eliminiamo dalla lista */
  151. char * del_client(char * ip, int portaudp) {
  152.     Tnodo * L = lista;
  153.     Tnodo * LP = NULL;
  154.     while (L != NULL) {
  155.         if(L->ip != NULL && L->portaudp != 0 && strcmp(L->ip, ip) == 0 && L->portaudp == portaudp) {
  156.             /* dopo aver trovato il nodo da eliminare: */
  157.             if(L->next != NULL) {
  158.                 /* se next è diverso da null settiamo L uguale al next, escludendo di fatti il nodo da eliminare */
  159.                 *L = *L->next;
  160.             } else {
  161.                 /* se next è null abbiamo due possibilità */
  162.                 if(LP != NULL) {
  163.                     /* se il precedente del nodo da eliminare è diverso da null il nodo da eliminare è l'ultimo, quindi settiamo il next del penultimo a null */
  164.                     LP->next = NULL;
  165.                 } else {
  166.                     /* se il precedente del nodo da eliminare è null (e il next è null) abbiamo un nodo solo, quindi annulliamo tutta la lista */
  167.                     lista = NULL;
  168.                 }
  169.             }
  170.             return "Utente eliminato.";
  171.         }
  172.         LP = L;
  173.         L = L->next;
  174.     }
  175.     return "Utente non presente.";
  176. }
  177.  
  178. /* dopo 'DEBUG' stampo tutta la lista a video senza inviarla ai client
  179.  * qui si possono inserire altri comandi per verificare lo stato del serve in esecuzione */
  180. void * debug_lista() {
  181.     Tnodo * L = lista;
  182.     while (L != NULL) {
  183.         printf("ip: %s, porta: %d, nick: %s, tcp: %d\n", L->ip, L->portaudp, L->nick, L->portatcp);
  184.         L = L->next;
  185.     }
  186.     fflush(stdout);
  187. }
  188.  
  189.  
  190.  
  191. int main(void) {
  192.     struct sockaddr_in server_socket, client_socket;
  193.     int s, i, client_lenght = sizeof(client_socket);
  194.     char buf[BUFLEN];
  195.     Tnodo tmp;
  196.  
  197.     if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
  198.         perror("socket");
  199.         exit(1);
  200.     }
  201.  
  202.     memset((void *)&server_socket, 0, sizeof(server_socket));
  203.     server_socket.sin_family = AF_INET;
  204.     server_socket.sin_port = htons(PORT);
  205.     server_socket.sin_addr.s_addr = htonl(INADDR_ANY);
  206.  
  207.     if (bind(s, (struct sockaddr *) &server_socket, sizeof(server_socket))==-1) {
  208.         perror("bind");
  209.         exit(1);
  210.     }
  211.     printf("Server attivo e in ascolto sulla porta %d\n",PORT);
  212.  
  213.     /* il server centrale resta sempre attivo */
  214.     while(TRUE) {
  215.         /* svuoto tutto il buffer altrimenti succederebbe:
  216.          * invio 'ciao' -> leggo 'ciao'
  217.          * invio 'come' -> leggo 'come'
  218.          * invio 'xx' -> leggo 'xxme'
  219.          * invio 'z' -> leggo 'zxme'
  220.          * da qui la necessità di svuotare il buffer.
  221.          */
  222.         memset(buf,'\0',BUFLEN);
  223.  
  224.         /* aspetto di ricevere un messaggio da qualunque client */
  225.         if(recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &client_socket, &client_lenght) == -1) {
  226.             perror("recvfrom()");
  227.         }
  228.  
  229.         if(strcmp("NAME|", substring(buf, 0, 5)) == 0) {
  230.             /* se il client sta inviando il suo nick lo inserisco nella lista, e chiedo la porta tcp */
  231.             char * nick = substring(buf, 5, strlen(buf) - 5);
  232.             printf("Un nuovo utente si è connesso:\n");
  233.             printf("IP ADDRESS -> %s\t UDP PORT -> %d \t New nick -> %s\n", inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port), nick);
  234.  
  235.             if(add_client(inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port), nick)) {
  236.                 if(sendto(s, "PROVIDE_TCP_PORT", BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  237.                     perror("sendto()");
  238.                 }
  239.             } else {
  240.                 if(sendto(s, "Nick non accettato.", BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  241.                     perror("sendto()");
  242.                 }
  243.             }
  244.         } else if(strcmp("TCP|", substring(buf, 0, 4)) == 0) {
  245.             /* se il client sta inviando la sua porta tcp, solitamente chiesta in automatico la inserisco nella lista */
  246.             int porta = atoi(substring(buf, 4, strlen(buf) - 4));
  247.             printf("TCP PORT ASSIGNED -> %d\n",porta);
  248.  
  249.             set_tcp_port(inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port), porta);
  250.             if(sendto(s, " ", 1, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  251.                 perror("sendto()");
  252.             }
  253.         } else if(strcmp("LISTA", buf) == 0) {
  254.             /* se un client sta chiedendo la lista dei client noti la invio */
  255.             if(sendto(s, get_clients(inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port)), BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  256.                 perror("sendto()");
  257.             }
  258.         } else if(strcmp("CONNECT|", substring(buf, 0, 8)) == 0) {
  259.             /* se un client sta chiedendo i parametri di un client li cerco nella lista e li invio */
  260.             char * nick = substring(buf, 8, strlen(buf) - 8);
  261.             if(sendto(s, get_client(nick), BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  262.                 perror("sendto()");
  263.             }
  264.         } else if(strcmp("DELETE", buf) == 0) {
  265.             /* se un client sta chiedendo di essere eliminato lo cancello dalla lista */
  266.             if(sendto(s, del_client(inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port)), BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  267.                 perror("sendto()");
  268.             }
  269.         } else if(strcmp("DEBUG", buf) == 0) {
  270.             /* eseguo il debug */
  271.             debug_lista();
  272.             if(sendto(s, buf, BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  273.                 perror("sendto()");
  274.             }
  275.         } else {
  276.             /* stampo a video qualunque comando non riconosciuto, il printf può essere eliminato, il sendto assolutamente no.
  277.              * anche dopo un comando errato il client si aspetta una risposta. */
  278.             printf("%s:%d -> %s\n", inet_ntoa(client_socket.sin_addr), ntohs(client_socket.sin_port), buf);
  279.             if(sendto(s, " ", BUFLEN, 0, (struct sockaddr *) &client_socket, client_lenght) == -1) {
  280.                 perror("sendto()");
  281.             }
  282.         }
  283.         fflush(stdout);
  284.     }
  285.  
  286.     close(s);
  287.     return 0;
  288.  }



Ultima modifica effettuata da pierotofy il 03/05/2011 alle 17:04
PM