Zócalo C: recv y envía todos los datos

6 minutos de lectura

Zocalo C recv y envia todos los datos
lorenzo cinque

Me gustaría obtener un comportamiento similar a este:

  1. ejecución del servidor
  2. ejecución del cliente
  3. El cliente escribe un comando como “ayuda” u otro
  4. El servidor responde apropiadamente
  5. ir a 3

El problema es que cuando mi función excCommand(“ayuda”) se ejecuta, solo se recibe e imprime un pequeño texto. Mi archivo de texto es este:

COMMAND HELP:

help - Display help
quit - Shutdown client

sólo se imprime COMMAND HELP. Otro problema es que cuando escribo un comando, no se imprime nada y después de 2 comandos, el cliente sale. Esta es la pieza en particular:

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

Este es el servidor:

#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--;
        }

    }

}

Manipulador:

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);
}

y este es mi cliente:

#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);
}

lo siento por ser tan extenso

  • La próxima vez que tenga una pregunta, intente construir un programa lo más pequeño posible que simule un comportamiento similar, será mucho más fácil para las personas entender cuál es el problema y ayudarlo.

    – Jah

    20 de noviembre de 2012 a las 18:43

  • tienes razón, lo siento por esto 🙁

    – Lorenzo Cinque

    20 de noviembre de 2012 a las 18:49

Zocalo C recv y envia todos los datos
Jah

los recv() y send() funciones no garantizan enviar/recibir todos los datos (ver hombre recv, hombre enviar)

Necesitas implementar tu propia send_all() y recv_all()algo como

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;
}

La siguiente guía te puede ayudar Guía de Beej para la programación de redes

  • ok, pero por otro lado, ¿cómo sé cuántas veces tengo que llamar a recv ()?

    – Lorenzo Cinque

    20 de noviembre de 2012 a las 18:45

  • Puede agregar la longitud del mensaje antes de cada mensaje. Y recv() fijó el número de bytes que representan la longitud del tamaño del mensaje, y luego llamó a recv(message_size)

    – Jah

    20 de noviembre de 2012 a las 19:21


  • Esta función send_all() no funciona. Debería declarar ‘buffer’ como ‘char *’; debería incrementar ‘buffer’ en ‘i’ cada vez que ‘i’ es positivo; y, por supuesto, debería detenerse por completo si ‘i’ es negativo.

    – usuario207421

    26/03/2014 a las 21:58

  • Y todo el asunto es innecesario. los send() el método se bloquea hasta que se hayan transferido todos los datos o se produzca un error. En modo de bloqueo, por supuesto, pero eso es lo que asume este código. Una implementación sin bloqueo tendría que usar select() para saber cuándo escribir a continuación.

    – usuario207421

    5 de julio de 2015 a las 22:43


1647267546 876 Zocalo C recv y envia todos los datos
usuario207421

Problemas habituales.

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);

Inválido. numBytesRecv podría haber sido cero, en cuyo caso no hay ningún mensaje en absoluto; de lo contrario, en este punto debe ser positivo, ya que ya probó negativo, e indica la longitud real del mensaje, que no necesariamente termina en nulo . Cambiar a:

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

y luego:

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

Inútil. Eliminar.

    }
    while (numBytesRecv > 0);

En este punto, debe comprobar si numBytesRecv < 0 y llama perror() o uno de sus amigos.

Elijo enviar antes de cada envío () si tengo que continuar o no.

así que primero tengo 3 definidos

#define BUFFSIZE 1024
#define CONT "CONT"
#define DONE "DONE"

Luego a enviar mis datos

int     send_to_socket(int sock, char *msg)
{
    size_t  len;
    int     ret[2];

    len = strlen(msg);
    ret[0] = send(sock, (len <= BUFFSIZE) ? DONE : CONT, 4, 0);
    ret[1] = send(sock, msg, BUFFSIZE, 0);
    if (ret[0] <= 0 || ret[1] <= 0)
    {
        perror("send_to_socket");
        return (-1);
    }
    if (len > BUFFSIZE)
        return (send_to_socket(sock, msg + BUFFSIZE));
    return (1);
}

Y para recibirlo:

char    *recv_from_socket(int cs)
{
    char    state[5];
    char    buff[BUFFSIZE+1];
    char    *msg;
    int     ret[2];

    msg = NULL;
    while (42)
    {
        bzero(state, 5);
        bzero(buff, BUFFSIZE+1);
        ret[0] = recv(cs, state, 4, 0);
        ret[1] = recv(cs, buff, BUFFSIZE, 0);
        if (ret[0] <= 0 || ret[1] <= 0)
        {
            perror("recv_from_socket");
            return (NULL);
        }
        // strfljoin() is selfmade
        // join the string and free the left argument to prevent memory leaks.
        // return fresh new string
        msg = (msg) ? ft_strfljoin(msg, buff) : strdup(buff);
        if (strncmp(state, DONE, 4) == 0)
            break ;
        i++;
    }
    return (msg);
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad