rohit
rohit

Reputation: 13

Not receiving full data

I have the following socket code in C. I am trying to receive 70 bytes of data on each cycle. However, I am getting only 4 bytes of data. The full data is something like this (in hex):

4D43475000856308000004B2DE1F04009E00200100000000696CF7AB002F1A00000000
000000325C000402069BFDE70857E22502F41C000036000000DF0B0932100B09DC0719

What is the problem? I have tried to research many StackOverflow answers, but with no help.

The code is as below:

void doprocessing (int sock);

int main( int argc, char *argv[] ) {
    int sockfd, newsockfd, portno, clilen;
    char buffer[1024];
    struct sockaddr_in serv_addr, cli_addr;
    int n, pid;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
        perror("ERROR opening socket");
        exit(1);
    }

    /* Initialize socket structure */
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 14064;

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    /* Now bind the host address using bind() call.*/
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR on binding");
        exit(1);
    }

    /* Now start listening for the clients, here
     * process will go in sleep mode and will wait
     * for the incoming connection
    */

    listen(sockfd,5000);
    clilen = sizeof(cli_addr);

    while (1) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

        if (newsockfd < 0) {
            perror("ERROR on accept");
            exit(1);
        }

        /* Create child process */
        pid = fork();

        if (pid < 0) {
            perror("ERROR on fork");
            exit(1);
        }

        if (pid == 0) {
            /* This is the client process */
            close(sockfd);
            doprocessing(newsockfd);
            exit(0);
        }
        else {
            close(newsockfd);
        }

    } /* end of while */
}

void doprocessing (int sock) 
{
    int n,i;
    unsigned int *buffer = malloc(1024);

    n = read(sock,buffer,1023);

    if (n < 0) {
        perror("ERROR reading from socket");
        exit(1);
    }

    printf("Here is the message: %.4x\n",*buffer);

    n = write(sock,"MCGP",18);

    if (n < 0) {
       perror("ERROR writing to socket");
       exit(1);
    }
    free(buffer);
}

Upvotes: 0

Views: 59

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595369

There are quite a number of bugs in your code:

  1. clilen = sizeof(cli_addr); needs to be moved inside of the while loop above the accept() call.

  2. unsigned int *buffer should be unsigned char *buffer instead.

  3. Why are you reading 1023 bytes when you are only expecting 70 bytes?

  4. You need to call read() in a loop until you actually receive all of the bytes you are expecting. read() can return fewer bytes than requested. TCP is a byte stream, it has no concept of message boundaries, the read will return whatever bytes are currently available, so it will return at least 1 byte up to the requested number of bytes.

  5. Your printf() call is only outputting the first 4 bytes of buffer, it is not outputting the full content of buffer. The return value of read() tells you how many bytes were actually received. Loop through the buffer outputting each byte individually.

  6. write(sock,"MCGP",18) is a buffer overflow, since you are only passing 5 bytes (4 characters and the null terminator) but are telling it to send 18 bytes instead.

Try this instead:

void doprocessing (int sock);

int main( int argc, char *argv[] ) {
    int sockfd, newsockfd, portno;
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t clilen;
    int pid;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);   
    if (sockfd < 0) {
        perror("ERROR creating socket");
        exit(1);
    }

    /* Initialize socket structure */
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 14064;

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    /* Now bind the host address using bind() call.*/
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR on bind");
        exit(1);
    }

    /* Now start listening for the clients, here
     * process will go in sleep mode and will wait
     * for the incoming connection
    */

    if (listen(sockfd, SOMAXCONN) < 0) {
        perror("ERROR on listen");
        exit(1);
    }

    while (1) {
        clilen = sizeof(cli_addr);

        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) {
            perror("ERROR on accept");
            exit(1);
        }

        /* Create child process */
        pid = fork();

        if (pid < 0) {
            perror("ERROR on fork");
            exit(1);
        }

        if (pid == 0) {
            /* This is the client process */
            close(sockfd);
            doprocessing(newsockfd);
            exit(0);
        }
        else {
            close(newsockfd);
        }

    } /* end of while */
}

void doprocessing (int sock) 
{
    int n, i;
    unsigned char buffer[70], *p = buffer;
    size_t len = 70;

    do {
        n = read(sock, p, len);
        if (n < 0) {
            perror("ERROR reading from socket");
            exit(1);
        }

        if (n == 0) {
            perror("DISCONNECTED unexpectedly");
            exit(1);
        }

        p += n;
        len -= n;
    }
    while (len > 0);

    printf("Here is the message: ");
    for (i = 0; i < 70; ++i)
        printf("%.02x", buffer[i]);
    printf("\n");

    n = write(sock, "MCGP", 4);
    if (n < 0) {
       perror("ERROR writing to socket");
       exit(1);
    }
}

Upvotes: 3

Related Questions