C socket: recv and send all data

95,104

Solution 1

The recv() and send() functions do not guarantee to send/recv all data (see man recv, man send)

You need to implement your own send_all() and recv_all(), something like

bool send_all(int socket, void *buffer, size_t length)
{
    char *ptr = (char*) buffer;
    while (length > 0)
    {
        int i = send(socket, ptr, length);
        if (i < 1) return false;
        ptr += i;
        length -= i;
    }
    return true;
}

The following guide may help you Beej's Guide to Network Programming

Solution 2

Usual problems.

void excCommand(char *command)
{
    if ( send(sock, command, strlen(command), 0) < 0)
        ErrorWithSystemMessage("send() failed");

    char replyMessage[BUFSIZE];
    ssize_t numBytesRecv = 0;
    do
    {
        numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
        if ( numBytesRecv < 0)
            ErrorWithSystemMessage("recv() failed");
        printf("%s\n", replyMessage);

Invalid. numBytesRecv could have been zero, in which case there is no message at all, otherwise at this point must be positive, as you've already tested for negative, and it indicates the actual length of the message, which isn't necessarily null-terminated. Change to:

    if (numBytesRecv == 0)
        break;
    printf("%.*s\n", numBytesRecv, replyMessage);

and then:

        memset(&replyMessage, 0, sizeof(replyMessage));

Pointless. Remove.

    }
    while (numBytesRecv > 0);

At this point you should check for numBytesRecv < 0 and call perror() or one of its friends.

Share:
95,104
Lorenzo Cinque
Author by

Lorenzo Cinque

Updated on January 24, 2020

Comments

  • Lorenzo Cinque
    Lorenzo Cinque over 4 years

    I would like to obtain a behavior similar to this:

    1. Server run
    2. Client run
    3. Client type a command like "help" or other
    4. Server responds appropriately
    5. go to 3

    The problem is that when my function excCommand("help") run just a little text is received and printed. My text file is this:

    COMMAND HELP:
    
    help - Display help
    quit - Shutdown client
    

    only COMMAND HELP is printed. Another problem is that when i type a command nothing is printed and after 2 command client exit. This is the piece in particular:

    while (quit)
        {
            getLine("client> ", command, 10);
            if (strcmp(command, "quit") == 0)
                quit = 0;
            else
                excCommand(command);
        }
    

    This is the server:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include "common.h"
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
            ErrorWithUserMessage("Parameter(s)", "<Server Port>");
    
        char *service = argv[1];
    
        int servSock = SetupTCPServerSocket(service);
        if (servSock < 0)
            ErrorWithUserMessage("SetupTCPServerSocket() failed: ", "unable to establish");
    
        unsigned int childProcessCount = 0;
        while (1)
        {
            int clntSock = AcceptTCPConnection(servSock);
    
            pid_t processID = fork();
            if (processID < 0)
                ErrorWithSystemMessage("fork() failed");
            else if (processID == 0)
            {
                close(servSock);
                HandleTCPClient(clntSock);
                exit(EXIT_SUCCESS);
            }
    
            printf("with child process: %d\n", processID);
            close(clntSock);
            childProcessCount++;
    
            //clean up zombies
            while (childProcessCount)
            {
                processID = waitpid((pid_t) - 1, NULL, WNOHANG);
                if (processID < 0)
                    ErrorWithSystemMessage("waitpid() failed");
                else if (processID == 0)
                    break;
                else
                    childProcessCount--;
            }
    
        }
    
    }
    

    Handler:

    void HandleTCPClient(int clntSock)
    {
        char buffer[BUFSIZE];
        ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
        buffer[numBytesRcvd] = '\0';
        if (numBytesRcvd < 0)
            ErrorWithSystemMessage("recv() failed");
        if (strcmp(buffer, "help") == 0)
        {
            FILE *fp = fopen("help.txt", "r");
            if (fp)
            {
                char line[128];
                while (fgets(line, sizeof(line), fp) != NULL)
                {
                    if (send(clntSock, line, sizeof(line), 0) < 0)
                        ErrorWithSystemMessage("send() failed");
                }
                fclose(fp);
            }
        }
    
        close(clntSock);
    }
    

    and this is my client:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include <sys/types.h>
    #include <sys/socket.h>
    
    #include "common.h"
    
    int sock;
    
    void getLine(char *message, char *buf, int maxLen)
    {
        printf("%s", message);
        fgets(buf, maxLen, stdin);
        buf[strlen(buf) - 1] = 0;
    }
    
    void excCommand(char *command)
    {
        if ( send(sock, command, strlen(command), 0) < 0)
            ErrorWithSystemMessage("send() failed");
    
        char replyMessage[BUFSIZE];
        ssize_t numBytesRecv = 0;
        do
        {
            numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
            if ( numBytesRecv < 0)
                ErrorWithSystemMessage("recv() failed");
            printf("%s\n", replyMessage);
            memset(&replyMessage, 0, sizeof(replyMessage));
    
        }
        while (numBytesRecv > 0);
    }
    
    void PrintFile(const char *filename)
    {
        FILE *fp;
        fp = fopen(filename, "r");
        if (fp)
        {
            char line[128];
            while (fgets(line, sizeof(line), fp) != NULL)
                fputs(line, stdout);
            fputs("\n", stdout);
            fclose(fp);
        }
    }
    
    int main(int argc, char *argv[])
    {
        int quit = 1;
        char command[10];
    
        if (argc < 2 || argc > 3)
        {
            ErrorWithUserMessage("Parameter(s)", "<Server Address> <Server Port>");
        }
    
        char *server = argv[1];
        char *service = argv[2];
    
        sock = SetupTCPClientSocket(server, service);
        if (sock < 0)
            ErrorWithUserMessage("SetupTCPClientSocket() failed: ", "unable to connect");
    
        printf("Connection established!\n\n");
    
        PrintFile("menu.txt");
        excCommand("help");
    
        while (quit)
        {
            getLine("client> ", command, 10);
            if (strcmp(command, "quit") == 0)
                quit = 0;
            else
                excCommand(command);
        }
    
        fputs("\n", stdout);
        close(sock);
        exit(EXIT_SUCCESS);
    }
    

    sorry for being so long-winded