Search code examples
csocketstcp

Clinet-side read() gets random trailing characters to the message (TCP client-server using sockets)


Practicing C network programming: I am writing a simple TCP client-server application that is supposed to send a message (in a separate thread for each client) as a string from a the server to the client and print the message on the client side (latter on this will become a console shop app). I am sending the size of the message first, followed by the message itself using sockets, write() function. Server side:

void answer(void *arg) {
    struct thData tdL; 
    tdL= *((struct thData*)arg);

    // Welcome message
    char *initMsgToClient;
    getInitialMessage(&initMsgToClient);
    int len_initMsgToClient = strlen(initMsgToClient);

    // Returning message to client
    if ( write (tdL.cl, &len_initMsgToClient, sizeof(int)) <= 0 ) {
         printf("[Thread %d] ",tdL.idThread);
         perror ("[Thread] Error at write(): len_initMsgToClient to client.\n");
    }
    if (write (tdL.cl, initMsgToClient, len_initMsgToClient) <= 0) {
         printf("[Thread %d] ",tdL.idThread);
         perror ("[Thread]Error at write(): initMsgToClient to client.\n");
    }
    else
        printf ("[Thread %d] Message was sent with success.\n",tdL.idThread);

}

void getInitialMessage(char **paramMessage) {
    char *resultMessage = "Welcome to Console Shopper!";
    *paramMessage = resultMessage; 
}

And on the client side I am reading the size first and the message itself and printing it, but every time I run ./client I get different random trailing characters to the message. Client side:

char welcomeMessageFromServer[512];
int lenWelcomeMsg;
// Reading size of first mesage: lenWelcomeMsg
if (read(sd, &lenWelcomeMsg, sizeof(int)) < 0) {
    perror ("[client] Error reading len welcome message from server.\n");
}
// Reading initial message from server: welcomeMessageFromServer
if (read(sd, welcomeMessageFromServer, lenWelcomeMsg) < 0) {
    perror ("[client] Error reading welcome message from server.\n");
    return errno;
}
printf("%s",welcomeMessageFromServer);
printf("\n");

For simplicity, I omitted to add the code for sockets and threads handling, most of it is from a tutorial so it should be correct. I am pretty sure I am doing something wrong with the size of the message that is being sent/received. My output with multiple runs for ./client:

Welcome to Console Shopper!
Welcome to Console Shopper!�
Welcome to Console Shopper!������i0  
Welcome to Console Shopper!������UF+:  

Some of the times it gets it right. What should I correct in order to get the right message all the times?


Solution

  • // Reading initial message from server: welcomeMessageFromServer
    if (read(sd, welcomeMessageFromServer, lenWelcomeMsg) < 0) {
        perror ("[client] Error reading welcome message from server.\n");
        return errno;
    }
    printf("%s",welcomeMessageFromServer);
    

    You have two issues here:

    1. The %s format specifier is only for C-style strings. To make your received message a C-style string, you need to put a terminating zero byte on the end of it.

    2. The read function does not ensure that it receives all the bytes requested. You need to check the return value and call it again if you didn't get the whole message.

    Try a function like this:

    ssize_t readAll (int fd, void *vbuf, size_t count)
    {
         char *buf = (char *) vbuf;
         ssize_t read_so_far = 0;
         while (count > 0)
         {
             ssize_t ret = read(fd, buf, count);
             if (ret < 0)
                 return ret;
             if (ret == 0)
                 return read_so_far;
             count -= ret;
             read_so_far += ret;
             buf += ret;
         }
         return read_so_far;
    }
    

    Then you can do this:

    // Reading initial message from server: welcomeMessageFromServer
    if (readAll(sd, welcomeMessageFromServer, lenWelcomeMsg) != lenWelcomeMsg) {
        perror ("[client] Error reading welcome message from server.\n");
        return errno;
    }
    welcoemMessageFromServer[lenWelcomeMsg] = 0;
    printf("%s",welcomeMessageFromServer);