2010-11-16 12 views
11

Estoy intentando crear un servidor al que puedan conectarse varios clientes. Aquí está mi código hasta ahora:C, programación de socket: Conexión de múltiples clientes al servidor usando 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); 
} 

Servidor:

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; 
} 

Tan pronto como un cliente se conecta y envía su primer mensaje, el servidor sólo se ejecuta en un bucle infinito, y escupe basura de la matriz de mensajes. recv no parece recibir nada. ¿Alguien puede ver dónde me equivoco?

Respuesta

4

Dos cuestiones en su código:

  • que debe hacer en lugar de recv(clientsock[i], ...)

  • Después de que usted no comprueba si recv() fallado, y por lo tanto printf() imprime el buffer sin inicializar message, por lo tanto, la basura en la salida

1

Debe verificar el límite < = 0 en su bucle de lectura, antes de al que llama leer.

1

En el ciclo while para el servidor, cambie el código para hacer recv(i) en lugar de recv(clientsocks[i]). Implementé este código y funciona con este cambio.

0

que sustituyó a la otra persona con el siguiente y funciona

} 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

No necesita el 'bzero()'. Simplemente tome en cuenta el valor de retorno de recv(), por ejemplo, en 'printf (" ->%. * S \ n ", rval, buf);'. – EJP

0

1) Es una buena práctica utilizar PF_INET (familia de protocolos) en lugar de
AF_INET (familia de direcciones) durante la creación del zócalo.

2) dentro del tiempo (1) en bucle
cada vez es recomendable hacer sus readfds vacía mediante FD_ZERO (& readfds). en la llamada recv() debe usar i en lugar de clientsocks [i] tiene que comprobar que el valor de retorno de recv es negativo (lo que indica un error al leer) si ese es el caso no tiene que imprimir el mensaje. durante la impresión del mensaje, asegúrese de que stdout/server esté listo para escribirle algo, lo cual puede hacer utilizando writefds (tercer argumento de selección).

Cuestiones relacionadas