Tutorial - Aplicação em C para transferência de arquivo usando socket TCP e Thread

Aplicação baseada na arquitetura cliente-servidor escrita em C para realizar múltiplas conexões com diversos clientes para transferências de arquivos de qualquer tamanho. É uma ótimo exemplo para conhecer o funcionamento de thread com sockets e recursos em C para pesquisa em diretórios no Linux.

[ Hits: 21.325 ]

Por: Ronaldo Borges em 11/12/2015 | Blog: https://www.facebook.com/ronyjah1


Arquivo cliente, código em C - Transferência do arquivo



O cliente deve ser compilado e executado na máquina qual se queria receber o arquivo do servidor. No comando da aplicação cliente deve ser informado o endereço IP, a porta definida no servidor e o arquivo que quer ser obter do servidor.

Para compilar o código C da aplicação cliente copie e salve como cliente.c em sua máquina o arquivo abaixo e compile da seguinte forma:

gcc -o client client.c

Código C do cliente:

#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define MAX_MSG 1024

/*
 Cliente envia mensagem ao servidor e imprime resposta
 recebida do Servidor
 */

int main(int argc, char *argv[]) {
    FILE *received_file;
    received_file = fopen(argv[3], "w");
    ssize_t len;
    char buffer[BUFSIZ];
    int aba;

      if (argc != 4) {
        fprintf(stderr, "use:./cliente [IP] [Porta] [arquivo]\n");
        return -1;
    } else if (!isdigit(*argv[2])) {
        fprintf(stderr, "Argumento invalido '%s'\n", argv[2]);
        fprintf(stderr, "use:./cliente [IP] [Porta] [arquivo]\n");
        return -1;
    }

    // variaveis
    int socket_desc;
    struct sockaddr_in servidor;
    char *mensagem;
    char resposta_servidor[MAX_MSG];
    int tamanho;
    mensagem = argv[3];
    char* aux1 = argv[2];
    int portaServidor = atoi(aux1);

    /*****************************************/
    /* Criando um socket */
    // AF_INET = ARPA INTERNET PROTOCOLS
    // SOCK_STREAM = orientado a conexao
    // 0 = protocolo padrao para o tipo escolhido -- TCP
    socket_desc = socket(AF_INET, SOCK_STREAM, 0);

    if (socket_desc == -1) {
        printf("Nao foi possivel criar socket\n");
        return -1;
    }

    /* Informacoes para conectar no servidor */
    // IP do servidor
    // familia ARPANET
    // Porta - hton = host to network short (2bytes)
    servidor.sin_addr.s_addr = inet_addr(argv[1]);
    servidor.sin_family = AF_INET;
    servidor.sin_port = htons(portaServidor);

    //Conectando no servidor remoto
    if (connect(socket_desc, (struct sockaddr *) &servidor, sizeof (servidor)) < 0) {
        printf("Nao foi possivel conectar\n");
        return -1;
    }
    printf("Conectado no servidor\n");
    /*****************************************/


    /*******COMUNICAO - TROCA DE MENSAGENS **************/

    //Enviando uma mensagem
    //mensagem 1 enviando nome do arquivo.  
    if (send(socket_desc, mensagem, strlen(mensagem), 0) < 0) {
        printf("Erro ao enviar mensagem\n");
        return -1;
    }
    printf("Dados enviados\n");

    memset(mensagem, 0, sizeof mensagem);
    memset(resposta_servidor, 0, sizeof resposta_servidor);

    //Recebendo resposta do servidor
    //mensagem 2 recebendo que arquivo existe   
    if((tamanho = read(socket_desc, resposta_servidor, MAX_MSG)) < 0) {
        printf("Falha ao receber resposta\n");
        return -1;
    }

    printf("Resposta recebida: %s\n", resposta_servidor);
    if (strcmp(resposta_servidor, "200") == 0) {

        mensagem = "OK";
        //mensagem 3 enviado ok
        write(socket_desc, mensagem, strlen(mensagem));
        //mensagem 4 recebendo o tamanho do arquivo;
        memset(resposta_servidor, 0, sizeof resposta_servidor);
        read(socket_desc, resposta_servidor, 1024);

        int tamanhoDoArquivo = atoi(resposta_servidor);
        printf("\nTamanho do arquivo a ser copiado: %s \n", resposta_servidor);
        aba = tamanhoDoArquivo;

    }else{
        fprintf(stderr, "Arquivo nao encontrado no servirdor'%s'\n", argv[3]);
        close(socket_desc);
        printf("Cliente finalizado com sucesso!\n");
        return 0;
    }

    while (((len = recv(socket_desc, buffer, BUFSIZ, 0)) > 0)&& (aba > 0)) {
        fwrite(buffer, sizeof (char), len, received_file);
        aba -= len;
        fprintf(stdout, "Recebidos %d bytes e aguardamos :- %d bytes\n", len, aba);
        if (aba <= 0) {
            break;
        }
    }
    fclose(received_file);
    close(socket_desc);

    printf("Cliente finalizado com sucesso!\n");
    return 0;
}

Conclusão

Não é a forma profissional de se fazer uma aplicação cliente servidor para transferência de arquivos usando socket e thread, porém acredito que pode ser muito útil para aquelas que estão iniciando em programação C, thread e sockets. Desta forma sugiro esta esta aplicação é apenas de cunho didático.

Obrigado.

Página anterior    

Páginas do artigo
   1. Arquivo servidor, código em C - Thread + socket
   2. Arquivo cliente, código em C - Transferência do arquivo
Outros artigos deste autor

Tutorial hadoop - Guia prático de um cluster com 3 computadores

Leitura recomendada

O Modelo de Referência OSI

Monitorando o consumo de banda com Bwbar

Controlando UPLOAD com o CBQ

BSD Sockets em linguagem C

Criação e uso de um interpretador de script BrainFuck em C++

  
Comentários
[1] Comentário enviado por mvforce em 14/12/2015 - 15:50h

Parabéns pelo tutorial... código bem claro e limpo.
Seria bastante didático se você colocasse antes do código fonte uma sequencia das ações lógicas do programa.

[2] Comentário enviado por ronyjah em 14/12/2015 - 16:15h


[1] Comentário enviado por mvforce em 14/12/2015 - 15:50h

Parabéns pelo tutorial... código bem claro e limpo.
Seria bastante didático se você colocasse antes do código fonte uma sequencia das ações lógicas do programa.


Este é meu primeiro artigo deve haver bastante falhas. Vou seguir seu conselho nos próximos (será tutorial sobre sistemas distribuídos, assim que sair gostaria de receber sua opinião). Muito obrigado prezado Mvforce.

[3] Comentário enviado por JairPMJr em 03/03/2016 - 08:21h

Para o seu primeiro artigo, esta muito bom.

Meus parabéns, o código bem comentado.

Abraço.

[4] Comentário enviado por camus88 em 21/04/2016 - 17:58h

Com ficaria com a função fork()? Estou estudando tal função mas ainda não consegui aplicá-la nesta situação. O fork(), diferente do Threads, ele duplica o processo criandoum semelhante filho alterando claro o PID(proces ID), minha duvida é onde colocaria está função(Linsten, Bind, Accept, Socket) para que assim tivesse multiplo acesso? Segue meu código de transferência de arquivo...

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

#define NOME_ARQ_MAXLEN 128
#define TAMMAX_BLOCO 65536

int main(int argc, char *argv[]){
if (argc != 2) {
printf("uso: %s <porta>\n", argv[0]);
return 0;
}

int ls;
struct sockaddr_in addr;
struct sockaddr_in clt_addr;
int len_addr, clt;
char nome_arq[NOME_ARQ_MAXLEN];
int nr, ns;
int fd;
int nr_r;
char bloco[TAMMAX_BLOCO];

//socket()
ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ls == -1) {
perror("socket()");
return -1;
}

//bind()
addr.sin_port = htons(atoi(argv[1]));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(ls,
(struct sockaddr *)&addr,
sizeof(struct sockaddr_in)) == -1) {
perror("bind()");
return -1;
}

//listen()
if (listen(ls, 1024) == -1){
perror("listen()");
return -1;
}
while (1) {
len_addr = sizeof(struct sockaddr_in);
clt = accept(ls,
(struct sockaddr*)&clt_addr,
(socklen_t *)&len_addr);
if (clt == -1) {
perror("accept()");
continue;
}
bzero(nome_arq, NOME_ARQ_MAXLEN);
nr = recv(clt, nome_arq, NOME_ARQ_MAXLEN, 0);
if (nr == -1){
perror("recv()");
continue;
}
fd = open(nome_arq, O_RDONLY);
if (fd == -1) {
char *resp;
resp = strerror(errno);
send(clt, resp, strlen(resp), 0);
continue;
}
ns = send(clt, nome_arq, nr, 0);
if (ns == -1) {
perror("send(nome_arq)");
continue;
}

do {
bzero(bloco, TAMMAX_BLOCO);
nr_r = read(fd, bloco, TAMMAX_BLOCO);
if (nr_r > 0){
ns = send(clt, bloco, nr_r, 0);
if (ns == -1) {
perror("send(bloco)");
continue;
}
}
}while(nr_r > 0);
close(fd);
close(clt);
}
close(ls);
return 0;
}

[5] Comentário enviado por arthuraureliops em 19/03/2022 - 17:16h

Olá Ronaldo, gostaria de tirar uma dúvida com você, poderia me enviar seu contato?


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts