Protocolo para transmissão de arquivos via porta serial.

Esse foi um dos trabalhos da disciplina de Redes de Computadores I em que o objetivo era a implementação de um protocolo para transferir arquivos via porta serial. Abaixo está a descrição de como deveria ser a implementação e a construção do cabo serial.

TRABALHO PRÁTICO – REDES I

Objetivo: Elaborar um protocolo de rede baseado em três camadas: física (cabo), enlace e aplicação. A camada física consistirá de um cabo serial conectado às portas serias de dois microcomputadores. A confecção do cabo ficará a cargo da dupla. O desenvolvimento do protocolo deverá seguir a implementação da camada física, através da concepção do cabo de comunicação, a camada de enlace, através da implementação das características desta camada (Controle de fluxo, Detecção e correção de erros) e da implementação da camada de aplicação através do desenvolvimento de um software de transferência de arquivos.

O protocolo de comunicação (com suas camadas) poderá ser implementado tanto na linguagem de programação C, C++ e Java, ficando restrito aos sistemas operacionais Linux e FreeBSD.

Para a construção do cabo siga o modelo:

Instruções para compilar e executar o programa:

Primeiramente você devera conectar dois computadores através do cabo serial descrito acima. Após isso copie os arquivos fontes para os dois computadores. Antes de compilar você devera escolher o arquivo a ser transferido e inserir seu nome com a extensão no arquivo fonte main.c. Veja a imagem:

Para implementação foi usado Linux (Ubuntu). Caso queira rodar em sistemas Windows você deverá fazer as alterações necessárias.

Para compilar utilize o gcc pela linha de comando, entre em um terminal e digite:

# gcc -o protocolo main.c base64.c base64.h declaracoes.h definicoes.c serial.c serial.h

Após compilar os arquivos será gerado o executável, ainda no terminal digite:

# ./protocolo

Você devera ver uma tela como essa:

Você deverá escolher uma opção para o primeiro computador e outra opção para o segundo computador. De preferência escolha a opção 2″ Receber” para o primeiro computador e a opção “1 Enviar” para o segundo computador. Após isso o protocolo iniciara a transferência do arquivo, quando terminado, será impressa uma mensagem  de transferência completa.

Para maiores informações a respeito do funcionamento do protocolo e detalhes da sua implementação, consulte o “Documento de Requisito”  que  está disponivel ao final desse post.

Código Fonte do Protocolo.

Arquivo main.c

/*********************************
Autores: Fernando Krein Pinheiro
         Clovis Reschke
Data: 20/05/2009
Linguagem: C
========= IMPORTANTE ===========
O código esta livre para usar,
citar e compartilhar desde que
mantida sua fonte e seus autores.
Obrigado.
********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "declaracoes.h"
#include "base64.h"
#include "serial.h"

int main()
{
        char nome_arq[TAM_DADOS];
        char buffer[TAM_DADOS+(sizeof(int)*3)];
        int op=0;
        FILE * saida;
        char *ptr_arq;

	system("clear");
        printf("\n\t========================  SFTP  ==========================\n");
	printf("\t=====  Protocolo de Transferencia de Arquivos via Serial ====\n");
	printf("\t=========================================================\n\n\n");
	printf("Digite a Opcao:\n1 Enviar\n2 Receber\n[ ]\b\b");
	scanf("%d",&op);

	switch (op)
		{
		case 1 :
			{

			    int tamanho=0,indice=0,tipo=0,status=0,aux=0,cont=0;
			    pacote *p = (pacote*) malloc (sizeof(pacote));
			    strcpy(nome_arq,"Nome_do_seu_arquivo.rar");
                            char *ptr_arq = abre_arq(nome_arq);

                            p =  monta_pacote(indice,ptr_arq,1,nome_arq);
			    	   tamanho = p->tamanho;
                        	    pacote_to_string(p,buffer);
				    status = escrever_porta(buffer);
				    bzero(buffer, TAM_DADOS);
				    while(cont != 5)
				{
					sleep(1);
					status = ler_porta(buffer);
					if(status > 0)
					   cont=5;
					else
					{
					printf("Sem comunicação\n");
					cont++;
					}
				}
				    if(!teste_ACK(p))
				     {
					printf("Chegou ACK");
				     }
				    else
				    {
					printf("Manda novamente");
				    }
			break;
			}
	   case 2:
		{
			int tamanho=0,indice=0,tipo=0,status=0,aux=0,cont=0;
			pacote *p = (pacote*) malloc (sizeof(pacote));

			do{
			 	while(cont != 5)
				{
					sleep(3);
					status = ler_porta(buffer);

					if(status > 0)
					   cont=5;
					else
					{
					printf("Sem comunicação\n");
					cont++;
					}
				}

			p = string_to_pacote(buffer);

			if(!testa_crc(p,buffer))
			{
				if(p->tipo == 1)
				{
					tamanho = p->tamanho;
		 			ptr_arq = aloca_mem(tamanho);
					strcpy(nome_arq,p->dados);
					indice=0;
				}
				else if(p->tipo == 2 )
				{
					for(aux=0;aux < 100;aux++,indice++)
					ptr_arq[indice] = p->dados[aux];
        			}
				   sleep(2);
			           p =  monta_pacote(indice,ptr_arq,3,nome_arq);
                         	   pacote_to_string(p,buffer);
				   status = escrever_porta(buffer);

		         }
			printf("\n\n%d",indice);
		   }while(indice < tamanho);
			escreve_arquivo(ptr_arq,nome_arq,tamanho);
		 break;
		}
}
return 0;
}

Arquivo serial.c

Esse fonte é responsável por toda configuração da porta serial, caso tenha alguma duvida consulte os arquivos de configuração da porta serial no seu Linux.

#ifndef SERIAL_C
#define SERIAL_C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <shadow.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include "declaracoes.h"
#include "base64.h"

int abrir_porta()
   {
        int fd;
        fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
        if (fd == -1)
        {
            printf("\nErro em /dev/ttyS0\n");
            return -1;
        }
        else
           fcntl(fd, F_SETFL, 0);
        return (fd);
  }

void configure_port(int fd)
{
    struct termios arq_novo;

    tcgetattr(fd, &arq_novo);
    cfsetispeed(&arq_novo, B19200); // seta taxa de transmição
    cfsetospeed(&arq_novo, B19200); // seta de recepção
    arq_novo.c_cflag |= (CLOCAL | CREAD);
    arq_novo.c_cflag &= ~PARENB; // sem paridade
    arq_novo.c_cflag &= ~CSTOPB;
    arq_novo.c_cflag &= ~CSIZE;
    arq_novo.c_cflag |= CS8;
    arq_novo.c_cflag &= ~CRTSCTS;// desabilita controle de fluxo
    arq_novo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);// raw input, sem mexer nos chars
    arq_novo.c_oflag &= ~OPOST;// raw output
    arq_novo.c_iflag &= ~IXOFF;
    arq_novo.c_iflag &= ~IXON;
    arq_novo.c_cc[VMIN]  = TAM_DADOS+(sizeof(int)*3);
    arq_novo.c_cc[VTIME] = 0;

    tcsetattr(fd, TCSANOW, &arq_novo);
}

int escrever_porta(char *buffer)
    {
	int fd;
        fd=abrir_porta();
        configure_port(fd);
	tcflush(fd, TCOFLUSH);
	ssize_t saida;
        saida = write(fd,buffer,TAM_DADOS+(sizeof(int)*3));
       return saida;
    }

int ler_porta(char *buffer)
{
        int fd;
        fd=abrir_porta();
        configure_port(fd);
	ssize_t entrada;
	fcntl(fd, F_SETFL, FNDELAY);
	entrada = read(fd,buffer,TAM_DADOS+(sizeof(int)*3));
	tcflush(fd, TCIFLUSH);
	return entrada;
 }

void fechar_porta()
{
        int fd;
   	close(fd);
}
#endif

Arquivo serial.h

Arquivo fonte que contem os cabeçalhos e os protótipos das funções usadas no serial.c

#ifndef SERIAL_H
#define SERIAL_H
#include <stdio.h>

extern
int abrir_porta();

extern
void configure_port(int);

extern
int escrever_porta(char*);

extern
int ler_porta(char *);

extern
void fechar_porta();

#endif

Arquivo definicoes.c

Arquivo fonte responsável pela montagem dos pacotes de dados, manipulação do arquivo,  calculo do CRC e ACK.

#ifndef DEFINICOES_C
#define DEFINICOES_C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "declaracoes.h"
#include "serial.h"
#include "base64.h"

char *abre_arq(char *nome_arq)
{
    unsigned char caracter;
    FILE *entrada;
    FILE *saida;
    int aux;

    entrada = fopen (nome_arq, "r+b");
     	if(!entrada)
          printf("Não foi possível abrir arquivo:%s ",nome_arq);

    saida = fopen("base64.64","w+b");
     	if(!saida)
          printf("Não foi possível criar dependências");

    encode(entrada,saida);

    fclose(saida);
    fclose(entrada);

    saida = fopen ("base64.64", "r+b");
     	if(!saida)
            printf("Não foi possível criar dependências");

   	int posicao_inicial = ftell(saida);
        fseek(saida, 0, SEEK_END);
    	int tamanho = ftell(saida);
        fseek(saida, posicao_inicial, SEEK_SET);

      char *ptr = aloca_mem(tamanho);

    if (saida == NULL)
    	printf("Não foi possível criar dependências");
    else
        {
            int aux=0;
             while(!feof(saida))
                {
                    caracter = getc(saida);
                        if(!feof(saida))
                            {
		 		ptr[aux] = caracter;
			        aux++;
                            }
               }
        }

       fclose(saida);
       remove("base64.64");

       return ptr;
}

pacote* monta_pacote(int indice,char *ptr_arq,int tipo,char *nome_arq)
{
    int aux=0;
    pacote *p = (pacote*) malloc (sizeof(pacote));

    if (tipo == 1)
    {
		p->tipo = 1;
		p->tamanho = strlen(ptr_arq);
		strcpy(p->dados,nome_arq);
          	return p;

     }
    else if (tipo == 2)
    {
		p->tipo=2;
                for(aux=0;aux < TAM_DADOS ;aux++,indice++)
                {
                    p->dados[aux]=ptr_arq[indice];

                }
                p->tamanho = sizeof(p->dados);;
   		return p;
    }
    else if (tipo == 3)
    {
        p->tipo=3;
        p->dados[0] = 'a';
        p->tamanho = sizeof(p->dados);
        return p;
    }
}

char *aloca_mem(int tamanho)
{
    char * ptr = (char*)malloc (tamanho * sizeof(char));
    if(!ptr)
    	printf("Não foi possível alocar memória");

    else return ptr;
}

short int CRC( char vetor[TAM_DADOS+(sizeof(int)*2)], int tam)
{

    short int crc = 0xffff;// 65535
    int j, i;
    for (j = 0; j < tam; j++)
    {

        crc = crc ^ vetor[j];
        for (i = 0; i < 8; i++)
        {
           crc = crc >> 1;
           if ((crc & 1) == 1)
             crc = crc ^ 0xA001;//40961
        }
    }
    return crc;
}
void pacote_to_string(pacote *p,char *buffer)
{
     int crc=0;

     memcpy(buffer, &p->tipo, sizeof(int));
     buffer += sizeof(int);
     memcpy(buffer, &p->tamanho, sizeof(int));
     buffer += sizeof(int);
     memcpy(buffer, &p->dados, TAM_DADOS);
     buffer += TAM_DADOS;
     p->crc = CRC(buffer, 108);
     memcpy(buffer, &p->crc, sizeof(short int));

        printf("\nmandou");
	printf("\ntipo: %d",p->tipo);
}

pacote *  string_to_pacote(char *buffer)
{

     pacote *p = (pacote*) malloc (sizeof(pacote));

     memcpy(&p->tipo, buffer, sizeof(int));
     buffer += sizeof(int);
     memcpy(&p->tamanho, buffer, sizeof(int));
     buffer += sizeof(int);
     memcpy(&p->dados, buffer, TAM_DADOS);
     buffer += TAM_DADOS;
     memcpy(&p->crc, buffer, sizeof(short int));

	printf("\n leu");
	printf("\ntipo: %d",p->tipo);
	return p;
 }

int testa_crc(pacote *p,char *buffer)
{
	short int crc=0;
	buffer += 108;
	memcpy(&crc, buffer, sizeof(short int));
	if(crc == p->crc)
		return 0;
	else
		return -1;
}

int teste_ACK(pacote *p)
{
	if (p->tipo == 3 && p->dados[0] == 'a')
		return 0;
	else
	        return -1;
}

int escreve_arquivo(char *ptr_arq,char *nome_arq,int tamanho)
{
    FILE *saida;
    FILE * arquivo;
    int aux;
        saida = fopen("base64.64","w+b");
            if(!saida)
            {
                printf("Não foi possível criar arquivo");
                return -1;
            }

            fprintf(saida,"%s",ptr_arq);
	fclose(saida);

        saida = fopen("base64.64","r+b");
            if(!saida)
            {
                printf("Não foi possível criar arquivo");
                return -1;
            }

	arquivo = fopen(nome_arq,"w+b");
            if(!saida)
            {
                printf("Não foi possível criar arquivo");
                return -1;
            }

	decode(saida,arquivo);

fclose(saida);
fclose(arquivo);
remove("base64.64");
return 0;
}

#endif

Arquivo declaracoes.h

Arquivo fonte que contem os cabeçalhos e protótipos das funções usadas no definicoes.c

#ifndef DECLARCOES_H
#define DECLARACOES_H
#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
#define TAM_DADOS 100
#include <stdio.h>

typedef struct pacote
{
	unsigned int tipo;
	unsigned int tamanho;
	short int crc;
	char dados[TAM_DADOS];
}pacote;

extern
short int calcula_CRC( char*, int);

extern
char* aloca_mem(int);

extern
char *abre_arq(char*);

extern
int escreve_arquivo(char *,char *,int);

extern
void pacote_to_string(pacote*,char*);

extern
pacote * string_to_pacote(char*);

extern
pacote * monta_pacote(int,char *,int,char*);

extern
int testa_crc(pacote*,char*);

extern
int teste_ACK(pacote *);
#endif

Arquivo base64.c

Arquivo fonte responsável pela codificação e descodificação na base 64, base padrão para codificação de caracteres para envio pela porta serial. Essa base também é utilizada pelos emails.

#ifndef BASE64_C
#define BASE64_C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "base64.h"
#define B64_DEF_LINE_SIZE   72
#define B64_MIN_LINE_SIZE    4
#define THIS_OPT(ac, av) (ac > 1 ? av[1][0] == '-' ? av[1][1] : 0 : 0)

static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";

void encodeblock( unsigned char in[3], unsigned char out[4], int len )
{
    out[0] = cb64[ in[0] >> 2 ];
    out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
    out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}

void encode( FILE *infile, FILE *outfile )
{
    unsigned char in[3], out[4];
    int i, len, blocksout = 0;

    while( !feof( infile ) ) {
        len = 0;
        for( i = 0; i < 3; i++ ) {
            in[i] = (unsigned char) getc( infile );
            if( !feof( infile ) ) {
                len++;
            }
            else {
                in[i] = 0;
            }
        }
        if( len ) {
            encodeblock( in, out, len );
            for( i = 0; i < 4; i++ ) {
                putc( out[i], outfile );
            }
            blocksout++;
        }
        if( blocksout >= (100/4) || feof( infile ) ) {
            if( blocksout ) {
                fprintf( outfile, "\r\n" );
            }
            blocksout = 0;
        }
    }
}

void decodeblock( unsigned char in[4], unsigned char out[3] )
{
    out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
    out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
    out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
}

void decode( FILE *infile, FILE *outfile )
{
    unsigned char in[4], out[3], v;
    int i, len;

    while( !feof( infile ) ) {
        for( len = 0, i = 0; i < 4 && !feof( infile ); i++ ) {
            v = 0;
            while( !feof( infile ) && v == 0 ) {
                v = (unsigned char) getc( infile );
                v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
                if( v ) {
                    v = (unsigned char) ((v == '$') ? 0 : v - 61);
                }
            }
            if( !feof( infile ) ) {
                len++;
                if( v ) {
                    in[ i ] = (unsigned char) (v - 1);
                }
            }
            else {
                in[i] = 0;
            }
        }
        if( len ) {
            decodeblock( in, out );
            for( i = 0; i < len - 1; i++ ) {
                putc( out[i], outfile );
            }
        }
    }
}

int b64( int opt, char *infilename, char *outfilename )
{
    FILE *infile;
    int retcode = 0;

    if( !infilename )
        infile = stdin;
    else
        infile = fopen( infilename, "rb" );

        FILE *outfile;
        if( !outfilename )
            outfile = stdout;
        else
            outfile = fopen( outfilename, "wb" );

            if( opt == 'e' ) {
                encode( infile, outfile);
            }
            else {
                decode( infile, outfile );
            }

            if( outfile != stdout ) {
                if( fclose( outfile ) != 0 ) {
                    retcode = 1;
                }
            }

        if( infile != stdin ) {
            fclose( infile );
        }
    return( retcode );
}
#endif

Arquivo base64.h

Arquivo fonte que contem os cabeçalhos e os prototipos das funções usadas no arquivo base64.c

#ifndef BASE64_H
#define BASE64_H
#include <stdio.h>

extern void encode( FILE *, FILE *);
extern void decode( FILE *, FILE *);

#endif

Caso tenha alguma dúvida a respeito do código fonte ou do seu funcionamento entre em contato. Para fazer o download do código fonte CLICK AQUI. Para fazer download do documento de Requisitos desse protocolo CLICK AQUI, esse documento foi feito como pré requisito para a aprovação da Disciplina de Engenharia de Software I na qual eu reaproveitei o software da disciplina de Redes de Computadores I.

About these ads
por ferpinheiro Postado em Redes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s