Socket TCP in C

Asked

Viewed 743 times

1

I’m having trouble sending a 32k buffer from a client to a server. For example: I have an A program on one machine, which is the client, and a B program on another machine, which is the server. When the client connects via socket, and sends the buffer, on the server it appears that only 7k were sent, someone knows why this problem occurs?

Client code:

int sock, conecta;
struct sockaddr_in cliente;

char buffer[32768]

// PRENCHE BUFFER COM \0
memset(buffer, '.', sizeof(buffer));

// INICIALIZA O SOCKET
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Erro socket.");
    exit(1);
}

// ESTRUTURA DO CLIENTE
cliente.sin_family = AF_INET; /* IPv4 */
cliente.sin_port = htons(15678); /* CONECTAR NA PORTA */
cliente.sin_addr.s_addr = inet_addr("127.0.0.1");  /* CONECTAR NO IP */
memset(&(cliente.sin_zero), '/0', 8);

printf("\nConectando ao servidor %s...\n", inet_ntoa(cliente.sin_addr));

// FAZ CONEXÃO COM O SERVIDOR
conecta = connect(sock, (struct sockaddr *)&cliente, sizeof(struct sockaddr));

if (conecta == -1) {
    printf("Porta fechada\n");
    exit(1);
} else
    printf("Conexao sucedida.\n");


// ENVIA BUFFER DE 32K

    enviarBuffer(sock, buffer, 32768);

Server code:

/* CRIANDO ESTRUTURA LOCAL(SERVIDOR) */
    localServ.sin_family = AF_INET; /* IPv4 */
    localServ.sin_port = htons(PORTA);
    localServ.sin_addr.s_addr = INADDR_ANY; /* DECLARA COMO 0.0.0.0 PARA FUNCIONAR COM QUALQUER IP DISPONIVEL */
    memset(&(localServ.sin_zero), '/0', 8);


    if((sockServ = socket(AF_INET, SOCK_STREAM, 0)) == ERR_CONECT_DB) {
        perror("Erro socket.");
        exit(1);
    }


    /* DECLARAÇÃO DO SOCKET() BIND() E LISTEN() DO SERVIDOR */

    if((bind(sockServ, (struct sockaddr *)&localServ, sizeof(struct sockaddr))) == ERR_CONECT_DB) {  /* ASSOCIA O SOCKET CRIADO À UMA PORTA */
        perror(("bind.\n"));
        exit(1);
    }

    if((listen(sockServ, BACKLOG)) == ERR_CONECT_DB) {  /* HABILITA CONEXÕES */
        perror("listen.\n");
        exit(1);
    }




    tamanho = sizeof(struct sockaddr_in);

        while(1) {
            if ((sockReceive = accept(sockServ, (struct sockaddr *)&remote, &tamanho)) < 0) {
                perror("accept");
                exit(1);
            } else {
                pid = fork();

                if(pid == 0) { // SE PROCESSO FILHO ...
                    close(sockServ); // ENCERRA PROCESSO PAI 


                    printf("Conexao recebida de %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
                    printf("PID: %d\n", getpid());

                    // RECEBE BUFFER DE 32K 
                   if((nBytes = recv(sockReceive, buffer, 32768, 0)) < 0) {
                        perror("buffer");
                        close(sockReceive);
                   } else 
                        printf("\nbuffer de solicitação recebido com %d Bytes\n", nBytes);


                }
            }

1 answer

3


You gotta put the recv() within a cycle until it returns 0.

char buffer[40000];
int bsize = 40000;
int blen = 0;

while (blen < bsize) {
    int bytes = recv(socket, buffer + blen, bsize - blen, 0); // recv() dentro dum ciclo
    if (bytes == 0) break;
    if (bytes == -1) /* erro */;
    blen += bytes;
}
buffer[blen] = 0; // se o buffer tiver texto e quiseres trata-lo como uma string

This is necessary because the internal functioning of the send() allows it to send pieces of the message in sequence. The process with the read() should pick up each piece and re-build the original message.


Note: the message sending process must follow a similar method with send()


You can read more about recv() and send() (in English) under reference POSIX.1-2017.

  • Cool, I think it worked!! Thanks ^^

  • Another thing, this loop also serves to send the buffer, IE, use send function()?

  • And it could also explain the need to do this?

  • To send just one send() with the complete content. If it is necessary to break the data into pieces, this is done internally by the send(), is not the responsibility of the programmer.

  • 2

    Negative @pmg - send() can only send one piece of data, and you need to loop just like recv(). It does not guarantee the sending of all data!!! The difference is that usually the sending buffer has enough space to receive 64k or 128k at once. But if you try to send a really large buffer, or the connection is slow and the upload buffer is full, send() will return a lower value than the buffer.

  • Thanks @epx, note added in my reply.

  • @pmg in the socket reference book, EINTR interruption is treated. It would not be interesting to include this in the response?

  • Thanks @lemoce, added links to the reference POSIX.1-2017

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.