CDS18
CDS18

Reputation: 19

Sockets-Double printing on client side

I'm developing a simple chat app using sockets. It's client-server driven. Everything works perfect, except for this bug I'm unable to find: if I'm the first client to connect to the server, every message I receive is printed just once on the screen (as it's supposed to be). Nevertheless, if I'm the second client who connects, every message I receive is printed twice, the third client see his messages three times, and so on. I'm really going crazy because of this:

When I receive something through the socket, I print it like this:

printf (" >%s \n", received);

Hence, if I get the message hello, sent by the user "charles" I print the message ">charles: hello", what amazes me is that the duplicate prints don't have the ">" character I added (the duplicate will be "charles: hello") , thus making me unable to find where the printing is being made (the printf() above is the only printf() I have in my code).

I'll appreciate any help. Here is the part of the code that receives from socket:

while (1) {
    recv(newsockfd, recibido, 255, 0);
    printf (">%s \n",recibido);
}

This code is executed by a thread.

Thanks, guys.

Here's the full code of the client:

void *Atender(void *estructura){
   DATOS *info;
   info = (DATOS *)estructura;
   int newsockfd=info->socket;
   char recibido[255];
   memset(recibido,1,255);
   while (1){
       recv(newsockfd, recibido, 255, 0);
       printf (">%s \n",recibido);
       memset(recibido,0,255);
   }
}

main(int argc, char *argv[]) {
    int sockfd;
    struct sockaddr_in serveraddr;
    char *server;
    Hilos = malloc((200)*sizeof(pthread_t));

    /* Remember the program name for error messages. */
    programname = argv[0];

    //Realizo lectura e imprimo para chequear que se leyo todo bien.
    lectura(argv,argc);

    /* Who's the server? */
    server=host;


    /* Get the address of the server. */
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(server);
    serveraddr.sin_port = htons(atoi(puerto));

    /* Open a socket. */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        fatalerror("can't open socket");

    /* Connect to the server. */
    if (connect(sockfd, (struct sockaddr *) &serveraddr,
        sizeof(serveraddr)) < 0)
        fatalerror("can't connect to server");

    enviarInfoInicial(sockfd,nombre,"Actual");

    char buff[200];
    memset(buff,1,200);


    //Creacion del hilo que se quedara siempre escuchando
    DATOS d;
    d.socket=sockfd;
    pthread_create(&Hilos[iterador_hilos],NULL,Atender,(void *)&d);
    iterador_hilos++;

    //El que no es un hilo se queda siempre esperando por si se quiere
    //introducir un comando
    while (1) {
        fgets(buff, sizeof buff, stdin);
        mandarInstruccion(sockfd,buff);
        if ((buff[0] == 'f') & (buff[1] == 'u') & (buff[2] == 'e')){
            printf("Cchat se ha cerrado. \n");
            close(sockfd);
            exit(0);
        }

        memset(buff,1,200);
    }
}

The code is in Spanish, but the general idea is understandable. The DATOS structure is just the structure i pass to the created thread, and only contains the socket from which that thread will be reading (the while(1) posted previously). "ATENDER" is the procedure the thread will execute.

Here's the relevant code from the server:

void EjecutarInstruccion(char tipo[],char argumento[],char usuario[]) {
    if (!strcmp(tipo,"men")) {
        char sala[20];
        char total[300];
        memset(total,0,300);
        strcpy(sala,ObtenerSalaUsuario(usuario));
        int i=0;
        for (i;i<200;i++) {
            if (!strcmp((lusuarios[i].sala),sala)) {
                strcat(total,usuario);
                strcat(total,": ");
                strcat(total,argumento);
                send (lusuarios[i].socket, total, strlen(total)+1, 0 );
            }
        }
    }
}

ON the server side I have an array of Users, each user contains his username, the chat room he is in and his socket (the fd). When the server needs to send a message, I go through the array of users and send the message to that user only if he's in the same chat room. Thanks.

Upvotes: 0

Views: 380

Answers (1)

usr
usr

Reputation: 171178

You don't check how many bytes recv returned. It does not necessarily read all data that is outstanding. You probably need to read in a loop until all bytes are received.

Upvotes: 2

Related Questions