Simulação de controle de fluxo usando sockets

Publicado por Perfil removido (última atualização em 10/08/2010)

[ Hits: 7.320 ]

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

Tratando o log do snmptrapd

Sockets: um mini webserver

Descritor de protocolo

Script de smbstatus

Connect - um simples programa para atravessar proxys Socks


  

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