Simulação de controle de fluxo usando sockets

Publicado por Ewerton Daniel de Lima (última atualização em 10/08/2010)

[ Hits: 7.168 ]

Download sockets.rar




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.

  



Esconder código-fonte

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

}

Scripts recomendados

Subdomain Finder

Descritor de protocolo

[C - Socket] UDP CLIENT

Mostrar IP em C#

Ruby


  

Comentários

Nenhum comentário foi encontrado.


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts