2010-11-16 9 views
11

Sto provando a creare un server a cui possono essere collegati più client. Ecco il mio codice finora:C, programmazione socket: connessione di più client al server utilizzando select()

Cliente:

int main(int argc, char **argv) { 

    struct sockaddr_in servaddr; 
    int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    if (sock == -1) perror("Socket"); 

    bzero((void *) &servaddr, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(6782); 
    servaddr.sin_addr.s_addr = inet_addr(<server_ip_address>); 

    if (-1 == connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr))) 
    perror("Connect"); 

    while(1) { 

    char message[6]; 
    fgets(message, 6, stdin); 

    message[5] = '\0'; 

    send(sock, message, 6, 0); 
    } 


    close(sock); 
} 

Server:

int main(int argc, char **argv) { 

    fd_set fds, readfds; 
    int i, clientaddrlen; 
    int clientsock[2], rc, numsocks = 0, maxsocks = 2; 

    int serversock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if (serversock == -1) perror("Socket"); 

    struct sockaddr_in serveraddr, clientaddr; 
    bzero(&serveraddr, sizeof(struct sockaddr_in)); 
    serveraddr.sin_family = AF_INET; 
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serveraddr.sin_port = htons(6782); 

    if (-1 == bind(serversock, (struct sockaddr *)&serveraddr, 
       sizeof(struct sockaddr_in))) 
    perror("Bind"); 

    if (-1 == listen(serversock, SOMAXCONN)) 
    perror("Listen"); 

    FD_ZERO(&fds); 
    FD_SET(serversock, &fds); 

    while(1) { 

    readfds = fds; 
    rc = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); 

    if (rc == -1) { 
     perror("Select"); 
     break; 
    } 

    for (i = 0; i < FD_SETSIZE; i++) { 
     if (FD_ISSET(i, &readfds)) { 
     if (i == serversock) { 
      if (numsocks < maxsocks) { 
      clientsock[numsocks] = accept(serversock, 
             (struct sockaddr *) &clientaddr, 
             (socklen_t *)&clientaddrlen); 
      if (clientsock[numsocks] == -1) perror("Accept"); 
      FD_SET(clientsock[numsocks], &fds); 
      numsocks++; 
      } else { 
      printf("Ran out of socket space.\n"); 

      } 
     } else { 
      int messageLength = 5; 
      char message[messageLength+1]; 
      int in, index = 0, limit = messageLength+1; 

      while ((in = recv(clientsock[i], &message[index], limit, 0)) > 0) { 
      index += in; 
      limit -= in; 
      } 

      printf("%d\n", index); 
      printf("%s\n", message); 

     } 
     } 
    } 
    } 

    close(serversock); 
    return 0; 
} 

Non appena un client si connette e invia il suo primo messaggio, il server appena viene eseguito in un ciclo infinito, e sputa fuori la spazzatura dalla matrice di messaggi. recv non sembra ricevere nulla. Qualcuno può vedere dove sbaglio?

risposta

4

Due questioni nel codice:

  • Si dovrebbe fare invece di recv(clientsock[i], ...)

  • Dopo di che non si controlla se recv() fallito, e quindi printf() stampa il buffer di Non inizializzato message, da cui la spazzatura nell'output

1

È necessario verificare il limite < = 0 nel ciclo di lettura, prima del si chiama lettura.

1

Nel ciclo while per il server, modificare il codice per fare recv(i) anziché recv(clientsocks[i]). Ho implementato questo codice e funziona con questo cambiamento.

0

ho sostituito l'altro con il sottostante e funziona

} else { 
/*     int messageLength = 5; 
        char message[messageLength+1]; 
        int in, index = 0, limit = messageLength+1; 

        memset (&message[index] , 0, sizeof (message [index])); 

        while ((in = recv(i, &message[index], limit, 0)) > 0) { 
         index += in; 
         limit -= in; 
        } 

        printf("%d\n", index); 
        printf("%s\n", message); 
*/ 
        bzero(buf, sizeof(buf)); 
        if ((rval = read(i, buf, 1024)) < 0) 
         perror("reading stream message"); 
        else if (rval == 0) 
         printf("Ending connection\n"); 
        else 
         printf("-->%s\n", buf); 

       } 
+0

Non è necessario il 'bzero()'. Basta prendere in considerazione il valore restituito da recv(), ad esempio in 'printf (" ->%. * S \ n ", rval, buf);'. – EJP

0

1) Si tratta di una buona pratica di utilizzare PF_INET (famiglia di protocolli) piuttosto che
AF_INET (famiglia di indirizzi) durante la creazione del socket.

2) entro il tempo (1) ciclo
ogni volta è consigliabile apportare le readfds vuota utilizzando FD_ZERO (& readfds). nella chiamata recv() si dovrebbe usare i piuttosto che clientsocks [i] è necessario controllare il valore di ritorno di recv è negativo (che indica errore nella lettura) se questo è il caso non è necessario stampare il messaggio. durante la stampa del messaggio assicurati che lo stdout/server sia pronto per scrivere qualcosa su di esso che puoi fare usando writefds (terzo argomento di select).

Problemi correlati