Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C socket: recv and send all data

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

like image 443
Lorenzo Cinque Avatar asked Nov 20 '12 18:11

Lorenzo Cinque


People also ask

Can sockets send and receive?

A socket is the interface between your application and the outside world: through a socket, you can send and receive data. Therefore, any network program will most likely have to deal with sockets, they are the central element of network communication.

What does recv () return?

If successful, recv() returns the length of the message or datagram in bytes. The value 0 indicates the connection is closed.

Does recv wait for data?

The recv() function receives a message from a socket. The recv() call can be used on a connection mode socket or a bound, connectionless socket. If no messages are available at the socket, the recv() call waits for a message to arrive unless the socket is nonblocking.

Is recv () a blocking call?

recv(IPC, Buffer, int n) is a blocking call, that is, if data is available it writes it to the buffer and immediately returns true, and if no data is available it waits for at least n seconds to receive any data.


2 Answers

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

like image 181
Jah Avatar answered Oct 08 '22 06:10

Jah


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.

like image 41
user207421 Avatar answered Oct 08 '22 06:10

user207421