Simulação de controle de fluxo usando sockets
Publicado por Ewerton Daniel de Lima (última atualização em 10/08/2010)
[ Hits: 7.204 ]
Segue uma simulação de controle de buffer de servidor e cliente em socket, efetuando transferência de arquivo do servidor para o cliente, controlando o streaming de bytes entre as máquinas.
//CLIENT #include<sys/socket.h> #include<sys/types.h> #include<netinet/in.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> //Taxa de consumo da aplicação #define TAXA_CONSUMO 100 //Controle de socket int sock; struct sockaddr_in address; //Controle de buffer int tamBuf = 0; char *buffer; //Controle de fila int inicio = 0; int fim = 0; int numElem = 0; //Nome do arquivo aberto char arquivo[100]; /* Inserção no buffer, baseada na estrutura de fila estática Recebe: - Elemento a inserir Devolve: - Sucesso da inserção: 0 ou -1 */ int inserir(char elemento) { if (numElem == tamBuf) { return -1; } else { buffer[fim] = elemento; fim = ((fim + 1) % tamBuf); numElem ++; return 0; } } /* Remoção do buffer, baseada na estrutura de fila estática Devolve: - Item removido ou -1 quando vazia */ char remover() { char aux; if (numElem == 0) { return -1; } aux = buffer[inicio]; inicio = ( (inicio + 1) % tamBuf ); numElem --; return aux; } /* Faz a conexão com o servidor; Recebe: -Endereço de IP ou hostname do servidor Devolve: -Sucesso da conexão: 0 ou 1; */ int conectar(char *server) { /* Criação de socket: - AF_INET : famÃlia de protocolos; - SOCK_STREAM : TCP; - 0 : IP; */ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) > 0) { printf("Socket configurado\n"); } address.sin_family = AF_INET; //AF_INET: Arpa Internet Protocols address.sin_port = htons(15000); //htons: Host to Network Short; //cria uma porta para conexão de número 15000 inet_pton(AF_INET,server,&address.sin_addr); //Estabelecimento de conexão if (connect(sock,(struct sockaddr *)&address,sizeof(address)) == 0) { return 1; } return 0; } /* Solicita lista de arquivos disponÃveis no servidor e imprime-a na tela. */ void solicitarLista() { char ask = 'l'; int nbytes, i; char arquivos[2000]; send(sock, &ask, sizeof(char), 0); recv(sock, &nbytes, sizeof(int), 0); recv(sock, arquivos, nbytes, 0); printf("\n\nPressione ENTER para visualizar lista de arquivos disponÃveis: "); getchar(); for (i=0; i<nbytes; i++) { printf("%c", arquivos[i]); } } /* Solicita um determinado arquivo e verifica se ele existe no servidor; Recebe: -Nome do arquivo solicitado; Devolve: -Resposta do servidor quanto à existência do arquivo: 0 ou 1; */ int solicitarArquivo(char *arquivo) { int tam; char c; tam = strlen(arquivo); printf("Arquivo solicitado no servidor..."); send(sock, arquivo, tam+1, 0); recv(sock, &c, 1, 0); if (c=='s') { return 1; } return 0; } /* Adiciona "quant" bytes contidos em "info" no buffer da aplicação. */ int adicionarNoBuffer(char *info, int quant) { int i; for (i=0; i<quant; i++) { inserir(*info); info++; } } /* Consome "quant" bytes do buffer da aplicação, gravando-os em no arquivo apontado por "file" Devolve: - Situação do buffer: 0 (normal), 1 (vazio) ou 2 (cheio); */ int consumirDoBuffer(int quant, FILE* file) { char c; int i, final; final = quant; if (quant>numElem) { final = numElem; } for (i=0; i<final; i++) { c = remover(); fwrite(&c, sizeof(char), 1, file); } if (numElem>=(tamBuf*0.9)) { return 2; } if (numElem<=(tamBuf*0.1)) { return 1; } return 0; } /* Imprime tela do aplicativo e barra de porcentagem de ocupação do buffer; Recebe: - Quantidade ocupada do buffer; - Tamanho total do buffer; */ void imprimirBuffer(int cheio, int tamanho) { float percentual; int i, final; percentual = ((float) cheio) / ((float) tamanho); final = (int) (percentual*79); system("clear"); printf("\n\n\ ___ ___ \n\ /\\__\\ /\\ \\ \n\ ___ /:/ / /::\\ \\ \n\ /\\__\\ /:/ / /:/\\:\\__\\\n\ /:/ / /:/ / ___ /:/ /:/ /\n\ /:/__/ /:/__/ /\\__\\ /:/_/:/ / \n\ /::\\ \\ \\:\\ \\ /:/ / \\:\\/:/ / \n\ /:/\\:\\ \\ \\:\\ /:/ / \\::/__/ \n\ \\/__\\:\\ \\ \\:\\/:/ / \\:\\ \\ \n\ \\:\\__\\ \\::/ / \\:\\__\\ \n\ \\/__/ \\/__/ \\/__/"); printf("\n\n\n\ ____ _____ ____ _____ _ __ __ ___ _ _ ____ \n\ / ___|_ _| _ \\| ____| / \\ | \\/ |_ _| \\ | |/ ___|\n\ \\___ \\ | | | |_) | _| / _ \\ | |\\/| || || \\| | | _ \n\ ___) || | | _ <| |___ / ___ \\| | | || || |\\ | |_| |\n\ |____/ |_| |_| \\_\\_____/_/ \\_\\_| |_|___|_| \\_|\\____|\n"); printf("\n\n\nPERCENTUAL OCUPADO DO BUFFER\n"); for (i=0; i<final; i++) { printf("#"); } for (i=final; i<79; i++) { printf("="); } printf("\n%.2f \% \n", percentual*100); } /* Salva o recebimento de streaming no arquivo apontado por "file"; Recebe: - Ponteiro para o arquivo em que deve-se escrever os bytes recebidos; Devolve: - Sucesso da operação: 0 ou 1; */ int salvarArquivo(FILE *file) { char bytes[200], md5[33], md5client[100]; char ack = 'a'; int nbytes, statusBuf, fimArq; FILE *md5file; if (!file) { return 0; } send(sock, &ack, sizeof(char), 0); //Envia ack do { recv(sock, &nbytes, sizeof(int), 0); //Tamanho do Segmento recv(sock, bytes, nbytes, 0); //Dados do segmento imprimirBuffer(numElem, tamBuf); adicionarNoBuffer(bytes, nbytes); statusBuf = consumirDoBuffer(TAXA_CONSUMO, file); send(sock, &statusBuf, sizeof(int), 0); recv(sock, &fimArq, sizeof(int), 0); } while (fimArq); while (numElem) { consumirDoBuffer(TAXA_CONSUMO, file); imprimirBuffer(numElem, tamBuf); } fclose(file); recv(sock, md5, sizeof(char)*32, 0); md5[32] = 0; printf("\n\nO md5sum do arquivo no servidor é %s", md5); sprintf(md5client, "md5sum %s > %s.md5", arquivo, arquivo); system(md5client); sprintf(md5client, "%s.md5", arquivo); md5file = fopen(md5client, "r"); fread(md5client, sizeof(char), 32, md5file); md5client[32] = 0; printf("\nO md5sum do arquivo recebido é %s", md5client); if (strcmp(md5, md5client)) { printf("\n\nHouve erros na transferência..."); } else { printf("\n\nO arquivo foi transferido de forma consistente..."); } getchar(); return 1; } /* Rotina principal */ int main() { int consumo = TAXA_CONSUMO; char serverName[20]; FILE *file; printf("Digite o IP ou hostname do servidor ao qual deseja de conectar: "); gets(serverName); if (conectar(serverName)) { printf("Conectado ao servidor!\n"); recv(sock, &tamBuf, sizeof(int), 0); //Recebe tamanho do buffer send(sock, &consumo, sizeof(int), 0);//Envia taxa de consumo buffer = (char *) malloc(sizeof(char)*tamBuf); solicitarLista(); printf("Digite um nome de arquivo para solicitar: "); gets(arquivo); if (solicitarArquivo(arquivo)) { printf("\nArquivo encontrado no servidor\n"); printf("\nEscolha o nome para salvar o arquivo: "); gets(arquivo); salvarArquivo(fopen(arquivo, "wb")); } else { printf("Arquivo não encontrado no servidor\n"); } } close(sock); } //SERVER #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<unistd.h> #include<stdlib.h> #include<stdio.h> //Controle de socket int sockServer, sockClient, addrlen; struct sockaddr_in address; //Controle de buffer int FATOR_BUFFER = 0; int tamBuf = 0; char *buffer, *bytes; //Controle de fila int inicio = 0; int fim = 0; int numElem = 0; //Nome do arquivo aberto char arquivo[100]; /* Inserção no buffer, baseada na estrutura de fila estática Recebe: - Elemento a inserir Devolve: - Sucesso da inserção: 0 ou -1 */ int inserir(char elemento) { if(numElem == tamBuf) { return -1; } else { buffer[fim] = elemento; fim = ((fim + 1) % tamBuf); numElem ++; return 0; } } /* Remoção do buffer, baseada na estrutura de fila estática Devolve: - Item removido ou -1 quando vazia */ char remover() { char aux; if (numElem == 0) { return -1; } aux = buffer[inicio]; inicio = ( (inicio + 1) % tamBuf ); numElem --; return aux; } /* Adiciona "quant" bytes, contidos no arquivo apontado por "file", no buffer da aplicação. */ int adicionarNoBuffer(int quant, FILE* file) { int i, lidos; lidos = fread(bytes, sizeof(char), quant, file); for (i=0; i<lidos; i++) { inserir(bytes[i]); } return lidos; } /* Consome "quant" bytes do buffer da aplicação, gravando-os na variável global "bytes"; Devolve: - Situação do buffer: 0 (normal), 1 (vazio) ou 2 (cheio); */ int consumirDoBuffer(int *quant) { int i, final; if (*quant>numElem) { *quant = numElem; } for (i=0; i<(*quant); i++) { bytes[i] = remover(); } if (numElem>=(tamBuf*0.9)) { return 2; } if (numElem<=(tamBuf*0.1)) { return 1; } return 0; } /* Configura o socket, inicia o servidor e espera pela conexão de cliente; Devolve: - 0 : caso em que não houve conexão de clientes; - 1 : caso em que o cliente efetuou a conexão; */ int iniciaServer() { system("clear"); /* Criação de socket: - AF_INET : famÃlia de protocolos; - SOCK_STREAM : TCP; - 0 : IP; */ if ((sockServer = socket(AF_INET, SOCK_STREAM, 0)) > 0) { printf("Socket criado\n"); } address.sin_family = AF_INET; //AF_INET: Arpa Internet Protocols address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(15000); //htons: Host to Network Short; //cria uma porta para conexão de número 15000 //Binding: associação de uma porta a um socket if (bind(sockServer,(struct sockaddr *)&address,sizeof(address)) == 0) { printf("Aguardando conexão...\n"); } //Listening: fica esperando uma conexão; //3: número de clientes que podem esperar na fila listen(sockServer, 3); addrlen = sizeof(struct sockaddr_in); //Abre mais uma porta para a conexão do cliente sockClient = accept(sockServer,(struct sockaddr *)&address,&addrlen); //sockCliente conecta com o cliente, enquanto sockServer espera outras conexões if (sockClient > 0) { return 1; } return 0; } /* Aguarda pela solicitação de arquivo pelo cliente. Ao receber a solicitação verifica a existência do arquivo no servidor e devolve o ponteiro para o arquivo, se o mesmo existir, ou, NULL caso não exista; */ FILE* aguardarSolicitacao() { char c = 's'; char ask, arquivos[2000]; int nbytes; FILE *lista, *file; recv(sockClient, &ask, sizeof(char), 0); if (ask=='l') { system("ls -x > lista"); lista = fopen("lista", "r"); nbytes = fread(arquivos, sizeof(char), 2000, lista); send(sockClient, &nbytes, sizeof(int), 0); send(sockClient, arquivos, nbytes, 0); } recv(sockClient, arquivo, 100, 0); file = fopen(arquivo, "rb"); if (file) { send(sockClient, &c, 1, 0); return file; } c = 'n'; send(sockClient, &c, 1, 0); return NULL; } /* Imprime tela do aplicativo e barra de porcentagem de ocupação do buffer; Recebe: - Quantidade ocupada do buffer; - Tamanho total do buffer; */ void imprimirBuffer(int cheio, int tamanho) { int i, final; float percentual; percentual = ((float) cheio) / ((float) tamanho); final = (int) (percentual*79); system("clear"); printf("\n\n\ ___ ___ \n\ /\\__\\ /\\ \\ \n\ ___ /:/ / /::\\ \\ \n\ /\\__\\ /:/ / /:/\\:\\__\\\n\ /:/ / /:/ / ___ /:/ /:/ /\n\ /:/__/ /:/__/ /\\__\\ /:/_/:/ / \n\ /::\\ \\ \\:\\ \\ /:/ / \\:\\/:/ / \n\ /:/\\:\\ \\ \\:\\ /:/ / \\::/__/ \n\ \\/__\\:\\ \\ \\:\\/:/ / \\:\\ \\ \n\ \\:\\__\\ \\::/ / \\:\\__\\ \n\ \\/__/ \\/__/ \\/__/"); printf("\n\n\n\ ____ _____ ____ _____ _ __ __ ___ _ _ ____ \n\ / ___|_ _| _ \\| ____| / \\ | \\/ |_ _| \\ | |/ ___|\n\ \\___ \\ | | | |_) | _| / _ \\ | |\\/| || || \\| | | _ \n\ ___) || | | _ <| |___ / ___ \\| | | || || |\\ | |_| |\n\ |____/ |_| |_| \\_\\_____/_/ \\_\\_| |_|___|_| \\_|\\____|\n"); printf("\n\n\nPERCENTUAL OCUPADO DO BUFFER\n"); for (i=0; i<final; i++) { printf("#"); } for (i=final; i<79; i++) { printf("="); } printf("\n%.2f \% \n", percentual*100); } /* Envia por um streaming de bytes o arquivo apontado por "file", efetuando o controle de fluxo através do uso do "buffer" e das variáveis addBytes e remBytes; */ void enviarArquivo(FILE *file) { char c, md5[100]; int addBytes = FATOR_BUFFER*2; int remBytes = FATOR_BUFFER; int statusBufClient = 0; int statusBuf = 0; int control = 1; FILE *md5file; if (!file) { return; } sprintf(md5, "md5sum %s > %s.md5", arquivo, arquivo); system(md5); sprintf(md5, "%s.md5", arquivo); md5file = fopen(md5, "r"); fread(md5, sizeof(char), 32, md5file); recv(sockClient, &c, sizeof(char), 0); //Recebe confirmação de inÃcio do { if (!(feof(file))) { adicionarNoBuffer(addBytes, file); } statusBuf = consumirDoBuffer(&remBytes); imprimirBuffer(numElem, tamBuf); send(sockClient, &remBytes, sizeof(int), 0); send(sockClient, bytes, remBytes, 0); recv(sockClient, &statusBufClient, sizeof(int), 0); if (statusBufClient==1) { remBytes = FATOR_BUFFER + (rand() % (FATOR_BUFFER/2)) + (FATOR_BUFFER/2); } if (statusBufClient==2) { remBytes = FATOR_BUFFER - (rand() % (FATOR_BUFFER/4)) - (FATOR_BUFFER/3); } if (statusBuf==1) { addBytes = remBytes*2; } if (statusBuf==2) { addBytes = remBytes/2; } send(sockClient, &numElem, sizeof(int), 0); } while (numElem); send(sockClient, md5, sizeof(char)*32, 0); return; } /* Rotina principal */ int main() { do { printf("\nTamanho do buffer do servidor (em bytes) (mÃn.: 2000): "); scanf("%d", &tamBuf); } while (tamBuf<2000); int tamBufClient = tamBuf/2; buffer = (char *) malloc(sizeof(char)*tamBuf); if (iniciaServer()) { printf("\nConexão estabelecida!"); send(sockClient, &tamBufClient, sizeof(int), 0); //Envia tamanho de buffer recv(sockClient, &FATOR_BUFFER, sizeof(int), 0); // Recebe taxa de consumo do client bytes = (char *) malloc(sizeof(char)*FATOR_BUFFER*2); printf("\nO tamanho do buffer do servidor é: %d", tamBuf); printf("\nO fator de buffer do cliente é: %d", FATOR_BUFFER); enviarArquivo(aguardarSolicitacao()); } else { printf("\nNão foi possÃvel conectar..."); } close(sockClient); close(sockServer); }
Simples servidor http com concorrência feito em C
Usando sockets para monitorar servidores
Calcular Broadcast e IPs disponíveis
Nenhum comentário foi encontrado.
Atualizar o macOS no Mac - Opencore Legacy Patcher
Crie alias para as tarefas que possuam longas linhas de comando - bash e zsh
Criando um gateway de internet com o Debian
Configuração básica do Conky para mostrar informações sobre a sua máquina no Desktop
Aprenda a criar músicas com Inteligência Artificial usando Suno AI
Instalando Zoom Client no Ubuntu 24.04 LTS
Instalando Zoom Client no Fedora 40
Instalando Navegador Firefox no Debian 12
Bloqueando propagandas no Youtube e outros sites com o uBlocker Origin