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.326 ]
Por: Ronaldo Borges em 11/12/2015 | Blog: https://www.facebook.com/ronyjah1
#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> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/sendfile.h> #include <ctype.h> #include <pthread.h> void *connection_handler(void *); #define MAX_MSG 1024 /* Servidor aguarda por mensagem do cliente, imprime na tela e depois envia resposta e finaliza processo */ int main(int argc, char* argv[]) { //Variaveis auxiliares para encontrar o arquivo a ser transferido. DIR *mydir; struct dirent *myfile; struct stat mystat; //verificando se foi executando o comando corretamente if (argc != 3) { fprintf(stderr, "use:./server [Porta] [local]\n"); return -1; } else if (!isdigit(*argv[1])) { fprintf(stderr, "Argumento invalido '%s'\n", argv[1]); fprintf(stderr, "use:./server [Porta] [local]\n"); return -1; } mydir = opendir(argv[2]); //verificando se o diretorio existe if(mydir == NULL ){fprintf(stderr, "Argumento invalido '%s'\n", argv[2]);return -1;} char* aux1 = argv[1]; int portaServidor = atoi(aux1); //variaveis int socket_desc, conexao, c, nova_conex; struct sockaddr_in servidor, cliente; char *mensagem; char resposta[MAX_MSG]; int tamanho, count; // para pegar o IP e porta do cliente char *cliente_ip; int cliente_port; //*********************************************************************// // INICIO DO TRATAMENTO DA THREAD, localização e transferência // // do arquivo. // //*********************************************************************// void *connection_handler(void *socket_desc) { /*********************************************************/ /*********comunicao entre cliente/servidor****************/ // pegando IP e porta do cliente cliente_ip = inet_ntoa(cliente.sin_addr); cliente_port = ntohs(cliente.sin_port); printf("cliente conectou: %s : [ %d ]\n", cliente_ip, cliente_port); // lendo dados enviados pelo cliente //mensagem 1 recebido nome do arquivo if ((tamanho = read(conexao, resposta, MAX_MSG)) < 0) { perror("Erro ao receber dados do cliente: "); return NULL; } resposta[tamanho] = '\0'; printf("O cliente falou: %s\n", resposta); char aux_nomeArquivo[MAX_MSG]; //fazendo copia do nome do arquivo para variavel auxiliar. tal variavel é utilizada para localizar // o arquivo no diretorio. strncpy(aux_nomeArquivo, resposta, MAX_MSG); //printf("ax_nomeArquivo: %s\n", aux_nomeArquivo); /*********************************************************/ if (mydir != NULL) { //funcao busca todo o diretorio buscando o arquivo na variavel aux_nomeArquivo //struct stat s; while ((myfile = readdir(mydir)) != NULL) { stat(myfile->d_name, &mystat); printf("Arquivo lido: %s, Arquivo procurado: %s\n", myfile->d_name, resposta); if (strcmp(myfile->d_name, resposta) == 0) {//arquivo existe closedir(mydir); //Reiniciando variáveis da pesquisa do diretorio para a proxima thread myfile = NULL; mydir = NULL; mydir = opendir(argv[2]); //**************************************// // INICIO DO PROTOCOLO // //*************************************// mensagem = "200"; //mensagem 2 - enviando confirmação q arquivo existe write(conexao, mensagem, strlen(mensagem)); //mensagem 3 - recebendo que arquivo OK do cliente read(conexao, resposta, MAX_MSG); //**************************************// // FIM DO PROTOCOLO // //*************************************// //abrindo o arquivo e retirando o tamanho// //fazendo copia do nome do arquivo para variavel auxiliar. tal variavel é utilizada para localizar // o arquivo no diretorio. char localArquivo[1024]; strncpy(localArquivo, argv[2], 1024); strcat(localArquivo,aux_nomeArquivo); FILE * f = fopen(localArquivo, "rb"); if((fseek(f, 0, SEEK_END))<0){printf("ERRO DURANTE fseek");} int len = (int) ftell(f); mensagem = (char*) len; printf("Tamanho do arquivo: %d\n", len); //convertendo o valor do tamanho do arquivo (int) para ser enviado em uma mensagem no scoket(char) char *p, text[32]; int a = len; sprintf(text, "%d", len); mensagem = text; //mensagem 4 - enviando o tamanho do arquivo send(conexao, mensagem, strlen(mensagem), 0); int fd = open(localArquivo, O_RDONLY); off_t offset = 0; int sent_bytes = 0; //localArquivo = NULL; if (fd == -1) { fprintf(stderr, "Error opening file --> %s", strerror(errno)); exit(EXIT_FAILURE); } while (((sent_bytes = sendfile(conexao, fd, &offset, BUFSIZ)) > 0)&& (len > 0)) { fprintf(stdout, "1. Servidor enviou %d bytes do arquivo, offset é agora : %d e os dados restantes = %d\n", sent_bytes, (int)offset, len); len -= sent_bytes; fprintf(stdout, "2.Servidor enviou %d bytes do arquivo, offset é agora : %d e os dados restantes = %d\n", sent_bytes, (int)offset, len); if (len <= 0) { break; } } //closedir(mydir); while (1) { } } }if(myfile==NULL) { //enviando mensagem para o cliente de arquivo nao encontrado. mensagem = "404";//file not found printf("\n//*********************************//\n"); printf("Arquivo \"%s\" Não Existe no diretório: \"%s\"\n",aux_nomeArquivo, argv[2]); //mensagem 2 - enviando confirmação q arquivo existe write(conexao, mensagem, strlen(mensagem)); //sempre que termina de pesquisar o diretorio de arquivos a variavel myfile vai para null // entao eh necessario preencher mydir novamente com o argv[2] com o diretorio de pesquisa. //caso contrario novas thread nao acessaram o diretorio passado em argv[2]] mydir = opendir(argv[2]); // while (1) { } close(conexao); //closedir(mydir); } if (mydir != NULL) { closedir(mydir); mydir = NULL; } } if (strcmp(resposta, "bye\n") == 0) { close(conexao); printf("Servidor finalizado...\n"); return NULL; } } //*********************************************************************// // FIM DO TRATAMENTO DA THREAD, localização e transferencia // // do arquivo. // //*********************************************************************// //************************************************************ /*********************************************************/ //Criando um socket socket_desc = socket(AF_INET, SOCK_STREAM, 0); if (socket_desc == -1) { printf("Nao foi possivel criar o socket\n"); return -1; } //Preparando a struct do socket servidor.sin_family = AF_INET; servidor.sin_addr.s_addr = INADDR_ANY; // Obtem IP do S.O. servidor.sin_port = htons(portaServidor); //Associando o socket a porta e endereco if (bind(socket_desc, (struct sockaddr *) &servidor, sizeof (servidor)) < 0) { puts("Erro ao fazer bind Tente outra porta\n"); return -1; } puts("Bind efetuado com sucesso\n"); // Ouvindo por conexoes listen(socket_desc, 3); /*********************************************************/ //Aceitando e tratando conexoes puts("Aguardando por conexoes..."); c = sizeof (struct sockaddr_in); while ((conexao = accept(socket_desc, (struct sockaddr *) &cliente, (socklen_t*) & c))) { if (conexao < 0) { perror("Erro ao receber conexao\n"); return -1; } pthread_t sniffer_thread; nova_conex = (int) malloc(1); nova_conex = conexao; if (pthread_create(&sniffer_thread, NULL, connection_handler, (void*) nova_conex) < 0) { perror("could not create thread"); return 1; } puts("Handler assigned"); } if (nova_conex < 0) { perror("accept failed"); return 1; } }
Tutorial hadoop - Guia prático de um cluster com 3 computadores
Monitorando o consumo de banda com Bwbar
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Criando uma VPC na AWS via CLI
Multifuncional HP imprime mas não digitaliza
Dica básica para escrever um Artigo.
Como Exibir Imagens Aleatórias no Neofetch para Personalizar seu Terminal
Pegar a ultima ocorrencia viva (1)
Pq me aparece isso quando fui atualizar o Ubuntu 24.10 no terminal? (1)
como coloco para instalar com esse erro. (13)
Alguém sabe de documentos de texto e /ou vídeo aulas de certificações ... (1)