Upload
buibao
View
218
Download
0
Embed Size (px)
Citation preview
TRANSFERÊNCIA E SINCRONIA DE PASTAS E ARQUIVOS
EM REDE LOCAL SEM NÓ CENTRALIZADOR
Gustavo de Oliveira Silva
Projeto de Graduação apresentado ao
Curso de Engenharia Eletrônica e de
Computação da Escola Politécnica,
Universidade Federal do Rio de Janeiro,
como parte dos requisitos necessários à
obtenção do título de Engenheiro.
Orientador:
Aloysio de Castro Pinto Pedroza, D.Sc.
Rio de Janeiro
Fevereiro de 2017
iv
Silva, Gustavo de Oliveira
Transferência e Sincronia de Pastas e Arquivos em
Rede Local sem Nó Centralizador / Gustavo de Oliveira
Silva – Rio de Janeiro: UFRJ / Escola Politécnica,
2017.
xi, 80 p.: il.; 29,7 cm.
Orientador: Aloysio de Castro Pinto Pedroza, D.Sc.
Projeto de Graduação – UFRJ/Escola Politécnica/
Curso de Engenharia de Eletrônica e de Computação,
2017.
Referências Bibliográficas: p. 75-76.
1. Transferência de Arquivos. 2. Rede Local. 3.
Sincronia de Pastas e Arquivos. 4. Identificação Única.
I. Pedroza, Aloysio de Castro Pinto. II. Universidade
Federal do Rio de Janeiro, Escola Politécnica, Curso de
Engenharia de Eletrônica e de Computação. III.
Transferência e Sincronia de Pastas e Arquivos em Rede
Local sem Nó Centralizador.
v
UNIVERSIDADE FEDERAL DO RIO DE JANEIRO Escola Politécnica – Departamento de Eletrônica e de Computação Centro de Tecnologia, bloco H, sala H-217, Cidade Universitária Rio de Janeiro – RJ CEP 21949-900
Este exemplar é de propriedade da Universidade Federal do Rio de
Janeiro, que poderá incluí-lo em base de dados, armazenar em computador,
microfilmar ou adotar qualquer forma de arquivamento.
É permitida a menção, reprodução parcial ou integral e a transmissão
entre bibliotecas deste trabalho, sem modificação de seu texto, em qualquer
meio que esteja ou venha a ser fixado, para pesquisa acadêmica, comentários e
citações, desde que sem finalidade comercial e que seja feita a referência
bibliográfica completa.
Os conceitos expressos neste trabalho são de responsabilidade do(s)
autor(es).
vi
AGRADECIMENTOS
À Microsoft, pois sem ela a essência desse projeto não existiria.
A meus familiares que sempre me apoiaram e me deram forças para
seguir em frente.
A meus amigos que me apoiaram e ajudaram com dicas e ideias em
alguns momentos.
A todas as pessoas que aceitaram o papel de cobaia para realizar alguns
testes.
E a mim mesmo, por encarado o problema e realizado a solução.
vii
Resumo do Projeto de Graduação apresentado à Escola Politécnica/UFRJ como parte dos requisitos necessários para a obtenção do grau de Engenheiro de Eletrônica e de Computação.
Transferência e Sincronia de Pastas e Arquivos em Rede Local sem Nó Centralizador
Gustavo de Oliveira Silva
Fevereiro/2017
Orientador: Aloysio de Castro Pinto Pedroza, D.Sc.
Curso: Engenharia Eletrônica e de Computação
Este trabalho corresponde a um programa desenvolvido para transferir e/ou sincronizar pastas e arquivos entre dois computadores conectados em rede local, incluindo um método para identificação única dos computadores para remover a necessidade de um nó central, que contenha a informação de cada computador, para isso, um computador deve formar um vínculo com outro para que possa realizar o processo de sincronia.
Palavras Chaves: Transferência, Sincronia, Rede Local, Identificação Única.
viii
Abstract of Undergraduate Project presented to POLI/UFRJ as a partial fulfillment of the requirements for the degree of Engineer.
Transfer and Synchronization of Files and Folders in
Local Area Network without Central Node
Gustavo de Oliveira Silva
February/2017
Advisor: Aloysio de Castro Pinto Pedroza, D.Sc.
Course: Electronics and Computing Engineering
This work corresponds to a program developed to transfer and/or synchronize folders and files between two computers connected in local area network, including a method for unique identification of the computers to remove the need of a central node, that contains the information of each computer, therefore, one computer must form a link with another so that it can perform the synchronization process.
Keywords: Transfer, Synchronization, Local Area Network, Unique Identification.
ix
SUMÁRIO 1. Introdução ................................................................................... 1
1.1. Motivação e Justificativa ....................................................................... 1
1.2. Objetivo ................................................................................................. 2
1.3. Organização e Abordagem ..................................................................... 2
2. Conceitos ..................................................................................... 4
2.1. Comunicação entre Computadores ........................................................ 4
2.1.1. TCP – Transmission Control Protocol ........................................ 4
2.1.2. UDP – User Datagram Protocol .................................................. 5
2.2. Serialização de Estruturas ..................................................................... 6
2.2.1. Binário ......................................................................................... 6
2.2.2. Texto ........................................................................................... 7
2.3. Criptografia ........................................................................................... 7
2.4. Reconhecimento na Rede ....................................................................... 8
2.5. Bibliotecas ............................................................................................. 9
2.6. Comentários ......................................................................................... 10
3. Cross-Compile ............................................................................ 11
3.1. Socket ................................................................................................... 11
3.1.1. Interface simples ......................................................................... 12
3.1.2. Interface completa ...................................................................... 12
3.2. Interface de Rede .................................................................................. 13
3.3. Operações com Arquivos ...................................................................... 13
3.4. Observações .......................................................................................... 14
4. Módulos Essenciais ..................................................................... 15
4.1. ByteStream ........................................................................................... 15
4.1.1. Em memória ............................................................................... 16
4.1.2. Em arquivo ................................................................................. 16
4.1.3. Em arquivo com escrita assíncrona ............................................. 17
4.2. DataStreamer ....................................................................................... 17
4.3. DirTree ................................................................................................ 19
4.3.1. Serialização em JSON ................................................................. 20
4.3.2. Adição de Nó .............................................................................. 21
4.3.3. Remoção de Nó ........................................................................... 22
4.3.4. Atualização de Árvore ................................................................ 22
4.3.5. Diferença entre Árvores .............................................................. 23
4.3.6. União de Árvores ........................................................................ 24
x
4.4. Tarefas em Segundo Plano ................................................................... 26
4.5. Conclusão ............................................................................................. 28
5. Conectividade ............................................................................. 29
5.1. Mensagens de Conectividade ................................................................ 29
5.2. Módulo do Núcleo de Conectividade .................................................... 32
5.3. Módulo de Notificação de Conectividade .............................................. 34
5.4. Considerações ....................................................................................... 36
6. Relacionamentos......................................................................... 37
6.1. Amigo ................................................................................................... 37
6.2. Módulo do Núcleo de Relacionamentos ................................................ 38
6.3. Módulo de Formação de Amizade ........................................................ 39
6.4. Módulo de Procura de Peer .................................................................. 42
6.5. Módulo de Validação de Amizade ........................................................ 43
6.6. Observações .......................................................................................... 44
7. Transferência de Arquivos ......................................................... 45
7.1. O Canal e suas Características ............................................................. 45
7.2. Estabelecendo a Conexão entre os peers ............................................... 47
7.3. Transferindo Arquivos .......................................................................... 49
7.4. Finalizando o Processo e Conclusões .................................................... 50
8. Sincronia de Pastas e Arquivos .................................................. 51
8.1. O Canal e suas Características ............................................................. 51
8.2. A Detecção de Diferenças ..................................................................... 52
8.3. Estabelecendo Conexão entre os Peers ................................................. 53
8.4. Operações do modo Cliente .................................................................. 55
8.5. Operações do modo Servidor ................................................................ 56
9. Experiências e Resultados .......................................................... 59
9.1. Reconhecimento de amizade ................................................................. 59
9.1.1. Objetivo ...................................................................................... 59
9.1.2. Equipamentos ............................................................................. 59
9.1.3. Preparações................................................................................. 59
9.1.4. Procedimentos ............................................................................ 60
9.1.5. Resultado .................................................................................... 60
9.1.6. Análise dos Resultados ............................................................... 61
9.1.7. Conclusão ................................................................................... 62
9.2. Sincronia de Pastas e Arquivos ............................................................ 62
9.2.1. Objetivo ...................................................................................... 62
xi
9.2.2. Equipamentos ............................................................................. 62
9.2.3. Preparações................................................................................. 62
9.2.4. Procedimentos ............................................................................ 62
9.2.5. Resultados .................................................................................. 63
9.2.6. Análise dos Resultados ............................................................... 65
9.2.7. Conclusão ................................................................................... 66
9.3. Taxas de transferência .......................................................................... 67
9.3.1. Objetivo ...................................................................................... 67
9.3.2. Equipamentos ............................................................................. 67
9.3.3. Preparações................................................................................. 67
9.3.4. Procedimentos ............................................................................ 67
9.3.5. Resultados .................................................................................. 68
9.3.6. Análise dos Resultados ............................................................... 68
9.3.7. Conclusões .................................................................................. 71
10. Conclusão ................................................................................... 72
10.1. Projetos Futuros ............................................................................... 73
Referências bibliográficas ................................................................... 75
Apêndice A ........................................................................................ 77
Apêndice B ........................................................................................ 80
1
CAPÍTULO 1
1. INTRODUÇÃO
No Windows 7, o mesmo programa que permite visualizar arquivos e
pastas, tanto locais quanto compartilhados na rede local, também permite
copiá-los. Entretanto, essas cópias, quando realizadas entre computadores na
rede, não apresentam taxas de transferência satisfatórias, pois outras aplicações
conseguem obter taxas maiores.
Existem empresas que oferecem serviço de armazenamento na nuvem.
Tais empresas costumam fornecer um programa que permite sincronizar uma
determinada pasta (configurável), em seu computador, com uma determinada
pasta (também configurável) no armazenamento na nuvem.
Diferente desses serviços, este projeto não possui um servidor central, que
contém todos os arquivos, informações e configurações de seus clientes, e
também não acessa a Internet para nada, tudo é realizado dentro da rede local
do usuário, permitindo taxas de transferência altas e comumente maiores que a
taxa de transferência que esse mesmo usuário possui na Internet.
Este projeto não apenas realiza uma simples transferência de arquivos
entre dois computadores, mas também é capaz de realizar sincronia de pastas
entre dois computadores. Outra característica do projeto é que o mesmo não é
exclusivo para Windows, ele também foi feito para ser executado em um sistema
operacional baseado em Linux. O Ubuntu 14.06 e suas versões seguintes foram
utilizados no desenvolvimento e testes do projeto.
1.1. MOTIVAÇÃO E JUSTIFICATIVA
A cópia de pastas e arquivos no Windows usando a ferramenta de
compartilhamento de pastas e arquivos nativa é realizada através do Windows
Explorer, outra ferramenta nativa do sistema operacional para explorar as
pastas do disco. Ou seja, da mesma forma que o usuário realiza operações nas
2
pastas e arquivos em seu computador, ele também pode realizar tais operações
envolvendo as pastas e arquivos de outro computador na rede.
Infelizmente é comum a obtenção de baixa taxa de transferência durante
transferências realizadas entre dois computadores com Windows 7 dentro na
mesma rede local, tal taxa é, inclusive, inferior à taxa de transferência máxima
(e comum) que era obtida, na mesma rede, ao realizar o download de um
arquivo da Internet, e com isso surgiu uma desconfiança de que esse problema
pudesse ser exclusivo da forma como a ferramenta de compartilhamento de
pastas e arquivos do Windows realiza essas operações.
1.2. OBJETIVO
De um modo geral, realizar transferência de arquivos entre dois
computadores com Windows em uma rede local, obtendo taxas de transferências
altas (em alguns casos atingindo a velocidade máxima da rede), ou seja, no
mínimo igual à taxa de transferência obtida ao se realizar o download de um
arquivo da Internet (considerando que a velocidade da conexão com a Internet é
inferior à velocidade máxima da rede local), é o principal objetivo deste projeto.
O projeto também é capaz de realizar sincronia de pastas e arquivos
entre dois computadores em rede local. Outra característica deste projeto é a
não necessidade de acesso à Internet e a não necessidade de um servidor para
centralizar as informações e configurações dos clientes.
1.3. ORGANIZAÇÃO E ABORDAGEM
Este trabalho possui 8 capítulos, além desta introdução e da conclusão ao
final.
No capítulo 2 serão apresentados os conceitos nos quais o projeto se
baseia.
No capítulo 3 serão apresentadas algumas particularidades existentes
entre as APIs (Application Programming Interface) do Windows e Linux.
No capítulo 4 serão abordados os módulos essenciais do projeto, que
realizam algumas das primordiais tarefas do mesmo.
No capítulo 5 serão apresentadas as formas como o projeto realiza a
comunicação entre computadores na rede.
3
No capítulo 6 será apresentada a forma como o projeto realiza o vínculo
entre os computadores.
No capítulo 7 está descrito o funcionamento da transferência de arquivos.
No capítulo 8 o funcionamento da sincronia de pastas e arquivo é descrito.
O capítulo 9 contém as experiências e seus resultados.
4
CAPÍTULO 2
2. CONCEITOS
O projeto foi criado usando a linguagem de programação C++ seguindo o
padrão C++11 [1] [2]. Para algumas funções, algumas bibliotecas foram
utilizadas, porém nenhuma dessas funções realiza o objetivo deste projeto, mas
elas são essenciais em determinadas partes. Adiante essas bibliotecas serão
apresentadas e quais recursos delas foram utilizados.
O projeto foi compilado usando o GNU Compiler Collection (GCC) [3]
nas versões 5.1, 5.3 e 6.1. Para compilar para o Windows foi utilizado o Mingw-
w64 [4] que é o GCC para Windows, com suporte ao Windows de 64 bits.
2.1. COMUNICAÇÃO ENTRE COMPUTADORES
Este projeto foi planejado e concebido na camada de aplicação do modelo
TCP/IP (Transmission Control Protocol/Internet Protocol) [5] [6]. Considerado
como pontos-finais (endpoint) de uma comunicação dentro de uma rede, o socket
é uma API que oferece acesso a funções, implementadas pelo sistema
operacional, que operam nas camadas mais baixas do modelo TCP/IP.
É necessário configurar o socket sobre a camada de transporte
(Transmission Control Protocol ou User Datagram Protocol) e a camada de
Internet (Internet Protocol versão 4, que é usado nesse projeto), antes de
realmente usar o socket.
Cada protocolo possui suas próprias características. A seguir serão
destacadas as principais características que foram consideradas para a escolha
do protocolo.
2.1.1. TCP – Transmission Control Protocol
É uma conexão de dois pontos apenas e é uma conexão garantida, ou seja,
uma vez estabelecida, há certeza de que está conectado ou não. A Figura 1
demonstra o diagrama de fluxo de operações que devem ser realizadas para
5
estabelecer uma conexão entre dois sockets configurados para usar o protocolo
TCP.
Há garantia de entrega e mantém a ordem dos pacotes, o que é essencial
para transmissão de dados maiores que o tamanho do pacote TCP.
Figura 1 – Diagrama de conexão TCP
2.1.2. UDP – User Datagram Protocol
Este protocolo não realiza uma conexão entre dois pontos. Nesse projeto
esse protocolo é usado exatamente para comunicações que não necessitam
conectar diretamente ao outro ponto, que é o caso do momento de descoberta de
outros computadores na rede através de broadcast.
Os pacotes transmitido e recebido são exatamente iguais. Isso faz com
que ao enviar uma mensagem por UDP, a mensagem estará inteira dentro do
pacote transmitido. Ao contrário do TCP, onde o envio de uma mensagem pode
ser fragmentado em mais de um pacote.
O UDP não garante a entrega do pacote e não garante a ordem de
entrega dos mesmos, por isso foi implementado a confirmação de entrega para
as mensagens que necessitam dessa confirmação.
Socket()
bind()
listen()
accept()
accept()
Socket()
Aguarda
até haver
conexão
Servidor
Cliente
Conexão
estabelecida
6
2.2. SERIALIZAÇÃO DE ESTRUTURAS
A fim de armazenar ou transmitir uma estrutura que se encontra em
memória, torna-se necessário a serialização da estrutura. Este processo consiste
em armazenar todos os tipos e valores de uma estrutura, em uma sequência de
bytes, de forma que seja possível recuperar a mesma estrutura a partir da
mesma sequência de bytes, ou seja, é uma operação reversível.
Embora possa parecer simples, deve-se tomar cuidado ao serializar uma
estrutura. Referência de memória não pode ser serializada, pois a posição de
memória pode variar (e geralmente varia) entre dois processos diferentes, mesmo
sendo o mesmo programa. Para esse caso, todos os dados da referência também
devem ser serializados.
O resultado da serialização pode conter apenas caracteres imprimíveis,
chamado de serialização em forma de texto, ou ser um stream binário.
2.2.1. Binário
A mensagem serializada é feita de forma binária, como uma cópia de
memória. Para strings não há muita diferença, mas para números (inteiro e
ponto flutuante) o resultado não é humanamente legível.
Neste projeto a serialização de strings é precedida de um número inteiro
sem sinal indicando o tamanho da string, isso remove o caractere nulo do final
da string do padrão C. O número inteiro que representa o tamanho da string, ao
ser serializado, pode ocupar 1, 2, 4 ou 8 bytes. Essa quantidade de bytes deve
ser indicada tanto ao serializar a string quanto ao desserializar.
A Figura 2 mostra um exemplo de mensagem de identificação de host
usado pelo projeto.
Figura 2 – Mensagem de MyCredential
Outra observação a se fazer com a serialização de números é devido ao
endianess, que é a ordem com que os bytes estão arranjados em memória, para
tipos de dados com mais de um byte. É chamado de big-endian quando o
primeiro byte de memória corresponde ao byte de maior peso. É chamado de
7
little-endian quando o primeiro byte de memória corresponde ao byte de menor
peso. A Figura 3 ilustra um determinado valor armazenado em memória em big-
endian e little-endian.
Neste projeto, todos os números são serializados em little-endian, existem
funções que garantem isso.
Figura 3 – Ilustração de um valor armazenado em little-endian e big-endian
2.2.2. Texto
Nesse modo a mensagem serializada possui maior facilidade para
compreensão humana.
Existem diferentes métodos de serialização em modo texto. Para este
projeto foi escolhido o JSON (JavaScript Object Notation) [7], devido à
facilidade em depurar, pois pode-se usar depuradores de JavaScript, e por ser
compacto, pois em alguns casos a estrutura serializada em JSON será
armazenada em banco de dados ou transmitida pela rede.
Foi utilizado o ASCII85, mais precisamente o ZeroMQ85, como forma de
codificar os números inteiros, mesmo utilizando JSON. Isso se deve ao caso,
ilustrado na Tabela 1, onde números muito grandes ocupam muito espaço ao
serem escritos por extenso, enquanto que ao codificar sempre ocuparão 5 bytes
(quando codifica um inteiro de 32 bits) ou 10 bytes (quando codifica um inteiro
de 64 bits).
Número: 578 1298230816
Hexadecimal: 00 00 02 42 4D 61 6E 20
ZeroMQ85: 0006! o<}]Z
Base 64: AAACQg== TWFuIA==
Tabela 1 – Comparação de codificação
2.3. CRIPTOGRAFIA
Este projeto utiliza AES (Advanced Encryption Standard) para realizar o
handshake necessário para realizar sincronia e algumas transferências. Esse
little-endian big-endian Número representado: 104105364
8
handshake é uma forma de autenticar o vínculo formado entre dois
computadores, conforme será explicado no capítulo 6.
2.4. RECONHECIMENTO NA REDE
Neste projeto existem duas formas de identificar um computador, ou seja,
pelo nome do computador (que pode ser modificado) e por uma identificação
única, que permanece transparente ao usuário. Uma das dificuldades foi definir
essa identificação única, pois deveria ter que garantir a unicidade do
computador perante qualquer rede.
A melhor opção de identificação única é o número de série de algum
componente de hardware do computador. Por exemplo, da CPU, mas essa
operação não existe nos processadores modernos devido a preocupações de
privacidade na época do Pentium III.
Devido à complexidade em obter o número de série de outros
componentes de hardware em cada sistema operacional, foi adotado o MAC
Address (Media Access Control Address) de alguma interface de rede do
computador por apresentar uma fácil forma de obtenção.
Embora não haja garantia de unicidade de MAC Address nas interfaces
de rede (além da possibilidade de modificar o MAC Address de algumas placas),
não há como existir dois ou mais computadores com o mesmo MAC Address em
uma rede local.
Na primeira execução do projeto, o MAC Address é obtido e armazenado
como sendo a identificação única. Nas demais execuções o projeto não inicia
caso a identificação única não seja o MAC Address de uma das placas de rede
do computador.
É definido como “amizade” o vínculo estabelecido entre dois
computadores, os quais são chamados de “amigo”. Esse vínculo é criado por meio
da execução da operação de formação de amizade do projeto e, durante essa
operação, duas chaves são negociadas. Essas chaves são utilizadas para o
handshake e para o possível futuro uso de criptografia em outras operações.
Os computadores se identificam na rede por meio de broadcast. Um
computador envia um broadcast informando quem ele é, e apenas os “amigos”
9
dele que estiverem na rede nesse momento é que respondem, em unicast, quem
são.
2.5. BIBLIOTECAS
Segue a lista de bibliotecas usadas no projeto.
• DIG-Logger [8]
Copyright © 2015-2016 Gustavo de Oliveira Silva. All rights reserved.
Biblioteca de mesma autoria que a deste projeto, para facilitar a exibição
e/ou armazenamento do log gerado no projeto.
• LibJSON [9]
Copyright © 2010 Jonathan Wallace. All rights reserved.
Biblioteca que realiza a codificação e decodificação em JSON.
• PolarSSL (mbed TLS) [10]
Copyright © 2006-2015, ARM Limited, All Rights Reserved.
Biblioteca usada para criptografia, apenas as funções para operação do
AES e cálculo de MD5 (Message-Digest algorithm 5) foram usadas.
• SQLite [11]
SQLite is in the Public Domain.
Biblioteca que implementa o banco de dados usado no projeto para
armazenar as informações e configurações do computador.
• Z85 [12]
Copyright © 2013 Stanislav Artemkin. All rights reserved.
Biblioteca que realiza a codificação e decodificação em ZeroMQ Base-85.
O código dessa biblioteca foi anexado ao código do projeto e modificado, pois
acrescentava um byte desnecessário ao resultado da codificação.
10
2.6. COMENTÁRIOS
Neste capítulo foi feito uma breve apresentação de alguns conceitos que
foram levados em consideração no desenvolvimento do projeto. Conforme esses
conceitos forem sendo usados na implementação, argumentado nas seções
seguintes, uma melhor explicação será apresentada.
Como foi de interesse do autor que este projeto funcionasse também no
sistema operacional Linux, algumas funções e estruturas foram criados para
manter o código independente da plataforma, e elas serão melhores abordadas
no próximo capítulo.
11
CAPÍTULO 3
3. CROSS-COMPILE
A essência deste projeto é independente do sistema operacional, porém a
implementação de alguns recursos usados pelo projeto são diferentes entre
alguns sistemas operacionais, como é o caso da manipulação de arquivos e o
acesso às funções nativas do sistema operacional.
O compilador Mingw-w64 possui a implementação de algumas funções da
API POSIX para o Windows, entretanto, algumas funções e macros variam nos
dois sistemas operacionais. Portanto, as seguintes implementações foram feitas
de forma a criar uma abstração maior para o código principal do projeto.
3.1. SOCKET
As funções e algumas macros usadas pela API do Windows são idênticas
às macros usadas na API POSIX, mas, devido à existência de macros diferentes,
foi necessária a criação de uma interface que isolasse, do código principal, o
código da implementação dependente do sistema operacional. Além disso, na
API do Windows é necessário executar uma função para inicializar o uso de
sockets pelo programa e, também na API do Windows, a função para obter o
código de erro do socket é diferente da usada na API POSIX.
Essa interface possuiu duas finalidades, oferecer compatibilidade entre
sistemas operacionais, ao mesmo tempo em que isola as dependências do sistema
operacional do resto do código, e oferecer simplicidade de uso por parte da
programação. A implementação dessa última finalidade possui um efeito
prejudicial, conforme será explicado adiante, e por isso outra implementação foi
feita.
12
3.1.1. Interface simples
Possui apenas cinco funções. Uma para definir as configurações do socket,
uma para inicializar o socket, uma para finalizar o socket, uma para enviar um
pacote e uma para receber um pacote.
É completamente funcional, mas tornou-se bastante complexa por ter que
oferecer suporte ao TCP e ao UDP, ao mesmo tempo em que oferece controles
simples. A função de receber pacote possui buffer interno, o que reduz a
eficiência do código, uma vez que o mesmo dado é copiado duas vezes, e esse
buffer possui tamanho fixo, que facilmente é contornado ao colocar um buffer
maior que o tamanho máximo de um pacote (64KB).
Mesmo com esses problemas, esse socket foi mantido para manter
compatibilidade com a parte do código até então implementada e que não sofria
perda significativa, que é o caso da comunicação via UDP realizada pelo núcleo
de conexão do projeto.
3.1.2. Interface completa
É assim chamada por ter as mesmas funções que a API POSIX para
operações com socket: create(), destroy(), bind(), setsockopt(), listen(),
connect(), accept(), close(), shutdown(), send(), sendto(), select(), recv() e
recvfrom().
Essas funções e seus argumentos são iguais às da API POSIX que foram
obtidas através do manual do Linux, com exceção de um grande fator, ao
implementar essa interface em C++, o socket passou a ser uma classe, portanto,
enquanto as funções da API POSIX requerem o socket em um de seus
argumentos, já na interface isso é omitido devido à orientação a objeto. As
funções de shutdown e select também possuem argumentos diferentes, pelo
mesmo motivo citado acima.
Essa implementação de interface de socket oferece completo controle
sobre o socket, que poderia ser realizado usando as funções nativas de socket.
Com isso, o problema do buffer que ocorria no modelo anterior não ocorre mais,
o que é essencial para um grande fluxo de dados. Outra característica é que esta
interface permite receber uma quantidade específica de bytes, e isso resolveu
outro problema que ocorre ao utilizar a outra interface com o protocolo TCP.
13
No TCP, ao executar a função send duas vezes, cada vez com dois bytes,
é possível que o socket que receba as mensagens, receba os quatro bytes em uma
única execução da função de recebimento. E isso trazia problemas para as
mensagens de controle que são transmitidas pelo socket, pois acabavam sendo
recebidas duas mensagens e eram tratadas como uma. Para evitar o uso de mais
um buffer, e ao mesmo tempo aproveitar do buffer do próprio socket, as
comunicações em TCP são feitas todas usando essa nova interface.
3.2. INTERFACE DE REDE
Um módulo foi criado para obter todas as interfaces de rede do
computador que, por estar nesse capítulo, possui implementação diferente para
cada sistema operacional, porém, em ambas as implementações, é obtido o nome
da interface de rede, a máscara de rede, o IP atribuído, o IP de broadcast e o
MAC Address da interface.
Este módulo inicia uma tarefa assíncrona dentro do próprio escopo do
programa principal que, de tempos em tempos, verifica as interfaces de rede
disponíveis, cria e disponibiliza uma lista com essas interfaces, além de uma lista
exclusiva contendo apenas as interfaces que estão conectadas em alguma rede.
Ao contrário da primeira lista, que normalmente permanece intacta desde
o início do programa, afinal, ela só é atualizada quando alguma interface de rede
é adicionada ou removida do computador, o que não é muito comum, a segunda
lista é modificada toda vez que alguma interface de rede se conecta ou
desconecta de alguma rede. Isso é de extrema importância para o envido de
broadcast na rede, pois ao enviar um broadcast no endereço 255.255.255.255 com
duas interfaces de rede conectadas, o sistema operacional escolhe uma das
interfaces para enviar o broadcast. Ao usar o IP de broadcast associado a uma
das interfaces, é assegurado que é essa interface de rede que será usada para
enviar o broadcast.
3.3. OPERAÇÕES COM ARQUIVOS
A linguagem de programação C++ em seu padrão C++11 possui
implementações para leitura e escrita de arquivos independente do sistema
operacional. Entretanto o sistema operacional Windows apresenta uma
particularidade na forma como trata a nomenclatura de pastas e arquivos.
14
A começar pelo uso da barra invertida (\), ao invés da barra (/), como
nos sistemas Linux. Outro fator é que a API do Windows trata os caracteres
estendidos de forma particular, usando o conceito de caractere largo (wide char).
Infelizmente, no padrão C++11, a classe que opera com arquivos com suporte
ao wide char requer que o conteúdo do arquivo também seja manipulado em
wide char, o que é inviável pois as operações de leitura e escrita nesse formato
só ocorrem em múltiplos de 2 (wide char corresponde a 2 bytes), logo arquivos
binários com tamanho ímpar não poderiam ser lidos ou gravados completamente.
Uma solução encontrada inicialmente foi o uso de uma biblioteca
chamada nowide, porém foi constatado uma taxa de escrita muito pequena em
relação ao uso da biblioteca padrão do C++11, o que tornou inviável o uso da
biblioteca devido à necessidade de alta taxa de leitura e gravação de arquivos.
Por isso, este projeto possui atual restrição de não realizar operações com
arquivos e pastas com caracteres estendidos em seus nomes.
3.4. OBSERVAÇÕES
Todas as strings dentro do programa são tratadas com codificação UTF-8
(8-bit Unicode Transformation Format), evitando, assim, problemas com o wide
char presente na API do Windows e, na maioria das vezes, o ambiente Linux
usa UTF-8 para as nomenclatura dos arquivos. O mesmo ocorre com o uso da
barra (/) ao invés da barra invertida (\) dentro do programa, mas para as
operações de escrita e leitura pela API do Windows é feito a conversão para a
barra invertida.
Outra particularidade envolvendo arquivos e o Windows será abordada
no capítulo seguinte, onde alguns módulos essenciais serão apresentados e
explicados.
15
CAPÍTULO 4
4. MÓDULOS ESSENCIAIS
Dentre os módulos criados, aqueles aqui apresentados são necessários e
úteis a cumprir o objetivo no qual foram baseados suas funcionalidades. Eles
podem ser entendidos como módulos primitivos, que exercem funções básicas
para as demais operações. Tais módulos não podem ser removidos e também
receberam maior atenção em sua implementação para serem confiáveis.
4.1. BYTESTREAM
Módulo que realiza operações com um array de bytes, similar à
implementação da string do padrão C++ (std::string), porém essa segunda não
foi adotada pois uma string em C é caracterizada como uma sequência de
caracteres até o primeiro caractere nulo (\0) e, como o módulo deveria operar
com arquivos binários também, essa restrição não deve existir.
Este módulo possui esse nome, pois também se assemelha à classe de
arquivos do C++ (std::fstream), possuindo funções de escrita, leitura e cursor.
Há apenas uma função de escrita (append) e ela pode receber quatro tipos
diferentes de estruturas: um caractere, um array de caracteres, junto com o
tamanho do mesmo, um std::string ou um ByteStream. Essa função copia o
conteúdo da estrutura, passada no argumento, no objeto atual com início na
posição indicada pelo cursor e move o cursor para até onde o conteúdo foi
copiado. Caso o cursor seja movido para depois do valor que marca o tamanho
do array, esse valor é atualizado para o valor do cursor.
A função de leitura (getStream) recebe, como argumento, a posição de
início da leitura e a quantidade de bytes que se deseja obter. E retorna um
ponteiro que aponta, em memória, para o início da sequência de bytes e contém,
no mínimo, a quantidade de bytes informada no argumento. É garantido que o
16
ponteiro retornado por essa função seja válido até que outra função seja
chamada nesse mesmo objeto.
Há também a função read que recebe, como argumento, um ponteiro para
uma sequência de bytes, que já deve estar alocado, e a quantidade de bytes que
se deseja ler. Nessa função o início da leitura de dados é passado pelo cursor do
módulo, e incrementado pela quantidade de bytes lidos, e o conteúdo é copiado
para dentro da região do ponteiro passado pelo argumento. Em caso de erro de
leitura a função retorna falso.
Conforme pode ser concluído das explicações anteriores, o cursor é usado
para posicionar o início da leitura e/ou escrita de dados e pode ser movido
livremente ao longo do array de bytes. O cursor não é usado na função de
leitura getStream pois esta é otimizada para operações com alta taxa de leitura,
pois reduz a quantidade de cópia de memória.
Esse módulo foi implementado de três formas diferentes para operar com
áreas diferentes e também fornecer otimização em uma das implementações.
4.1.1. Em memória
Essa implementação armazena todos os bytes apenas na memória do
computador.
A função append possui recurso de automaticamente ajustar o tamanho
do buffer interno conforme for necessário mais espaço. É uma funcionalidade de
grande utilidade, mas que deve ser evitada em larga escala, por isso a função
abaixo deve ser usada na maioria dos casos.
A função realloc tem como finalidade reservar um espaço em memória
maior ou igual ao tamanho informado no argumento da função. Quando o
tamanho do buffer interno é maior ou igual ao tamanho desejado na execução
da função, o buffer não é modificado. Caso o cursor esteja posicionado acima do
tamanho desejado, ele é movido para a nova posição final.
4.1.2. Em arquivo
Essa implementação realiza operações diretamente sobre a classe
std::fstream, inclusive as operações com o cursor. Existe um buffer interno que é
compartilhado para a função de leitura getStream e para a função de escrita
append, portanto, não é recomendável usar a mesma instância para leitura e
escrita.
17
O buffer é similar à implementação em memória, porém apenas a função
de leitura é que possui a capacidade de expandir automaticamente o buffer. Em
contrapartida, existe uma função exclusiva que pode ser usada para definir o
tamanho do buffer. É utilizada no DataStreamer (que será explicado mais a
frente) pois ler um trecho de um arquivo em disco com várias pequenas leituras
consome mais tempo do que ler o mesmo trecho do mesmo arquivo em disco de
uma única vez.
4.1.3. Em arquivo com escrita assíncrona
Essa é uma especialização do módulo de arquivo para realizar escrita em
arquivo de forma assíncrona. Usando o módulo de arquivo básico, após o buffer
ser preenchido, durante a chamada da função de escrita, todo o buffer é escrito
no arquivo. Isso tinha um efeito negativo na transferência de arquivos, pois toda
vez que o buffer ficava cheio, a transferência parava até que o buffer voltasse a
ficar vazio.
Essa especialização inicia um processamento paralelo (uma thread) que
realiza o processo de gravação do buffer em disco sempre que um buffer fica
cheio. A implementação também conta com uma fila que permite que exista
mais de um buffer, permitindo que enquanto existe um buffer sendo preenchido,
existe outro sendo gravado em disco. Quando a fila atinge sua capacidade
máxima, que por padrão é 256, mas pode ser modificada, a função de escrita do
ByteStream é bloqueada até que haja ao menos um espaço na fila.
4.2. DATASTREAMER
Módulo que realiza transferência de um ByteStream entre dois
computadores através da rede, conforme ilustrado na Figura 4, garantindo a
entrega, a ordem dos dados contidos no ByteStream e suporta transferência de
até (264 – 1) bytes.
Figura 4 – Diagrama de relacionamento entre o DataStreamer e o ByteStream
Computador A Computador B
ByteStream
DataStreamer
ByteStream
DataStreamer
18
No capítulo 2 desta monografia foram apresentadas algumas
características do TCP, dentre elas, a garantia de entrega e a ordem dos pacotes,
foram os fatores decisivos para a escolha do protocolo TCP para a realização da
transferência de dados na rede. Essa escolha reduziu a complexidade do
algoritmo do projeto, pois não foi necessária a criação de um algoritmo para
garantir a ordem dos bytes enviados, nem a criação de um algoritmo para
garantir a entrega.
A conexão realizada entre dois computadores através deste módulo segue
o mesmo conceito de uma conexão TCP, porém as operações de conexão de
socket são realizadas internamente no módulo. Existe uma única função que
estabelece a conexão, na qual informa-se o IP de destino, a porta que será usada
e o modo de conexão. Este último consiste em dizer se o módulo irá utilizar a
função accept ou a função connect do socket para estabelecer a conexão.
Além da função que encerra a conexão que esteja aberta no módulo,
existe uma função que envia os dados e outra função que recebe os dados. Essas
duas funções são complementares e precisam ser executadas uma em cada
computador para a transferência ser realizada. Tal transferência segue uma
sequência de operações, conforme pode ser observado no diagrama da Figura 5,
que correspondem ao controle do módulo.
A fim de facilitar a compreensão do módulo, servidor é o computador que
envia os dados e cliente é o computador que recebe os dados.
Ao iniciar o processo de transferência do módulo, o servidor envia para o
cliente o tamanho dos dados (em bytes) que serão transmitidos. O cliente
responde se aceita ou não a transferência. Para que o cliente aceite a
transferência, deve-se informar o tamanho dos dados ao executar a função de
recebimento do módulo. Após o servidor receber a resposta de aceitação do
cliente, inicia-se o processo de transmissão dos dados.
Os dados são fragmentados em segmentos, de tamanho inicial de 63KB,
e são transmitidos, dessa forma, direto pelo socket. Caso ocorra mais de três
erros de timeout na função de envio do socket ao enviar um mesmo segmento, o
tamanho do segmento é reduzido em 10%. Caso não ocorra erro na função de
envio do socket, o tamanho do segmento é aumentado em 10% até o limite de
63KB.
19
Figura 5 – Diagrama de transmissão do DataStreamer
Os segmentos sempre são enviados em ordem. Caso a função de envio do
socket falhe mais de cinco vezes, a operação é encerrada com erro. Caso a função
de recebimento do socket falhe mais de dez vezes, a operação é encerrada com
erro. Em ambos os casos de erro, o socket é fechado e o módulo é desconectado.
Após a transmissão de todos os segmentos, o servidor envia um byte
informando que a transmissão foi finalizada. Caso o cliente não receba esse byte,
um erro é retornado no servidor e no cliente.
4.3. DIRTREE
Este módulo é responsável por criar e manipular estruturas em árvore
que corresponde à estrutura de pastas e arquivos contidos no computador, ao
mesmo tempo em que fornece facilidade para realizar operações com essas
estruturas.
Cada ramo da árvore sempre será uma pasta. Todo arquivo sempre será
uma folha na árvore. A estrutura permite armazenar a data da última
Envia
Solicitação
Recebe
Resposta
Envia o
ByteStream
Envia Fim
Recebe
Solicitação
Envia Resposta
Recebe o
ByteStream
Recebe Fim
Aceitou? Não
Sim
Aceitou? Não
Sim
Fim
Fim
20
modificação, o tamanho e o MD5 de arquivos, sendo que os dois primeiros são
sempre obtidos ao se montar a estrutura usando as funções internas do módulo.
A data é armazenada como inteiro de 32 bits e é obtida por meio da função stat.
O cálculo do MD5 é opcional, pois é apenas utilizado para verificar se dois
arquivos são iguais e o tempo gasto para calcular esse valor não é algo que se
possa desconsiderar. Há também um atributo cuja finalidade é marcar a
operação realizada com aquela pasta ou arquivo (criação, edição ou remoção),
necessário no processo de sincronia de pastas e arquivos.
Todos os ramos e folhas da árvore estão organizados em ordem alfabética
de nome (da pasta ou arquivo), isso reduz a complexidade dos demais
algoritmos, além de fornecer otimização para algumas operações, conforme serão
explicadas adiante. A estrutura é case-sensitive em relação à nomenclatura das
pastas e arquivos. Mesmo que uma estrutura física de pastas e arquivos não
permita que exista uma pasta e um arquivo com o mesmo nome, essa estrutura
permite isso para poder realizar as operações de comparação, muito utilizadas
para realizar a sincronia de pastas e arquivos.
A estrutura pode ser criada “manualmente”, mas o módulo possui uma
função que monta toda a estrutura para uma desejada pasta, garantindo um
padrão para o preenchimento das estruturas da árvore. É importante observar
que essa função suporta path tanto no formato Windows quanto no formato
UNIX, embora internamente opere tudo no formato UNIX.
Outra característica desta função é que todos os ramos e folhas
correspondem a apenas uma pasta ou arquivo, mas apenas a raiz da árvore
corresponde ao path absoluto, que é informado no argumento da função.
É importante ressaltar que o nó de raiz da árvore não é usado em
nenhuma outra operação senão a de criação da árvore e a de leitura dos demais
nós com o path, sendo que neste último caso o nó de raiz pode ser ignorado por
meio de um argumento da própria função. As demais operações serão descritas a
seguir, tendo como premissa a estrutura e o preenchimento da mesma através
da função do próprio módulo para esta finalidade, descrita acima.
4.3.1. Serialização em JSON
A fim de poder salvar a estrutura no banco de dados (sem problemas com
informação em binário), transmitir a estrutura pela rede e por possuir
ferramentas acessíveis para a depuração, a serialização por meio de JSON foi
21
escolhida. Navegadores modernos, como Google Chrome e Mozilla Firefox
possuem um console JavaScript que permite executar comandos JavaScript
diretamente, onde um desses comandos é capaz de serializar e desserializar uma
estrutura em JSON.
Todo arquivo serializado em JSON possui a data de criação, data de
modificação e o tamanho do arquivo. Opcionalmente o MD5 pode ser adicionado
à estrutura serializada, visto que em algumas etapas não é necessário o envio do
MD5. O atributo de modificação também é opcional e é usado apenas no
processo de sincronia, a fim de informar que tipo de modificação o
arquivo/pasta sofreu.
Com exceção do atributo de modificação, os demais números são
codificados usando Z85 a fim de comprimir o resultado final, visto que, em
JSON, o número é escrito de forma literal, logo, números muito grandes ocupam
muito espaço, conforme Tabela 1 (página 7).
Todo nó é serializado como um array com seus elementos dispostos
seguindo os seguintes critérios: O primeiro elemento sempre será o nome do
arquivo ou pasta, o segundo elemento sempre será um array que armazena os
nós que são filhos do nó atual, ou seja, quando o nó atual é um arquivo, esse
array fica vazio, caso contrário, contém os arquivos e pastas do nó atual. Caso o
nó seja uma pasta, o terceiro elemento corresponde ao atributo de modificação e
é um elemento opcional. Caso o nó seja um arquivo, o terceiro elemento é o
tamanho do arquivo, o quarto elemento é a data de modificação, o quinto
elemento é o MD5 (que é opcional, mas se torna obrigatório quando o atributo
de modificação for serializado) e o sexto elemento é o atributo de modificação,
que é opcional.
4.3.2. Adição de Nó
O módulo possui duas funções que permitem adicionar um nó à estrutura
em árvore na posição desejada. Enquanto uma das funções recebe a posição do
nó como string no padrão UNIX para nomenclatura de pastas e arquivos, a
outra função recebe a própria estrutura de nó, que será copiada internamente,
porém não copia os filhos desse nó. Ao contrário da função que monta a
estrutura, essa função, que adiciona um nó, recebe, como argumento, as
informações do arquivo já preenchidas (caso seja arquivo).
22
A função ignora o path da raiz da árvore e cria a estrutura de pastas caso
ela não exista. Ou seja, ao adicionar um nó do tipo arquivo que esteja em uma
pasta que não pertença a atual estrutura, essa pasta será adicionada à estrutura,
mantendo o padrão da função de criação da árvore.
Por conveniência, na função de adição com base em outro nó, caso o nó
que se deseja adicionar já se encontra na árvore, a função pode atualizar as
informações do nó, para isso deve-se passar o argumento para a função de forma
a permitir a atualização, caso contrário, um erro é emitido.
Essa característica é usada na recepção de arquivos durante a sincronia
de pastas e arquivos, pois é possível que o arquivo recebido seja uma atualização
do arquivo existente.
4.3.3. Remoção de Nó
Diferente da função de adição de nó, a função de remoção de nó recebe,
como argumento, um nó de qualquer árvore e realiza a remoção do nó que
possui os mesmos pais (comparando o nome dos nós superiores) e o mesmo
nome e tipo. Ou seja, para remover um nó de uma árvore pode-se usar o próprio
nó na função, mas também se pode criar duas árvores com a mesma estrutura e
remover o nó de uma das estruturas usando o nó da outra estrutura equivalente.
O nó removido e os filhos desse nó são todos apagados da memória ao se
utilizar essa função. Portanto referências a esses nós se tornarão inválidas logo
após a operação de remoção.
4.3.4. Atualização de Árvore
Há uma função que atualiza todos os filhos de um nó de acordo com os
filhos do nó informado como referência. Note que a atualização só é realizada
com os filhos dos nós informados, além disso, devido a própria característica das
estruturas em árvore, os nós usados como principal e referência serão entendidos
como raiz de uma árvore.
Dois nós são considerados iguais se seus nomes, seus tipos (arquivo ou
pasta) e seus pais forem iguais. Caso a condição de igualdade seja verdadeira, o
nó da árvore principal será atualizado conforme os dados da árvore de referência.
Observe que dessa forma apenas os nós que são do tipo arquivo é que são
modificados, visto que pastas não possuem outros atributos além do nome e do
tipo, mas isso não é uma verdade constante, há um flag na função para atualizar
23
o atributo de modificação. Uma vez que tal flag esteja definido, o atributo de
modificação de todos os nós da árvore principal, que estiverem presentes na
árvore de referência, será atualizado para o valor contido na árvore de referência.
Adicionalmente, devido ao modo como o algoritmo percorre a estrutura,
uma flag foi acrescentada à função que permite que um nó de referência seja
inserido na árvore principal (junto com seus filhos) caso o mesmo não exista na
árvore principal. Pode parecer estranho, pois é uma operação de atualização,
mas o algoritmo de sincronia, em alguns momentos, necessita atualizar alguns
nós de uma árvore e inserir os nós que faltam.
4.3.5. Diferença entre Árvores
Este é um dos pontos principais desse módulo e faz parte da base do
módulo de sincronia de pastas e arquivos. Esta operação é realizada entre duas
árvores e resulta em listas contendo a diferença entre as árvores.
Figura 6 – Duas árvores para ilustrar o algoritmo de diferença de árvores
esquerda ambas direita
( , )
Tabela 2 – Resultado do algoritmo de diferença das árvores de exemplo
Considere duas árvores posicionadas lado a lado, conforme ilustrado na
Figura 6. O algoritmo retorna três listas, conforme pode ser observado na
Tabela 2. Uma das listas corresponde aos nós que estão na árvore da direita e
não estão na árvore da esquerda, identificada como lista da direita. Outra lista
corresponde aos nós que estão na árvore da esquerda e não estão na árvore da
direita, identificada como lista da esquerda. E a última lista corresponde aos
0
1
3 4 5
6 7
8
A 9 B
0
1 2
4 5
6 7
8
A 9 B
C
2
3 B B C
24
pares de nós que existem em ambas as árvores, mas apresentam informações
diferentes, identificada como lista central. Considerando essa característica,
conclui-se que a lista central somente pode conter arquivos.
Observe que para um nó pertencer a ambas as árvores é necessário que
eles possuam o mesmo nome, o mesmo tipo e os mesmos pais, idem ao modo de
comparação realizado na operação de atualização de nós. Atendendo a essa
condição, o algoritmo compara o tamanho do arquivo, a data de modificação e,
caso esteja disponível, o MD5. O algoritmo julga essas três informações e insere
ambos os nós na lista central se ao menos uma dessas informações for diferentes.
O algoritmo percorre a árvore da direita ao mesmo tempo em que
percorre a árvore da esquerda e aproveita o fato de que os filhos de cada nó
estão em ordem alfabética. O algoritmo será explicado de forma recursiva, mas
a sua implementação foi não recursiva, com o uso de pilhas para retornar ao
ponto anterior. Idem ao algoritmo de atualização de árvore, o algoritmo de
diferença de árvore ignora o nó de raiz da árvore.
Ao receber o ponteiro de um dos nós da árvore da esquerda e similar ao
da árvore da direita, o algoritmo percorre os filhos de ambos os nós, porém
baseia-se no nó da esquerda. Quando o filho do nó da esquerda possui nome que
antecede o nome do filho do nó da direita, o algoritmo assume que esse filho da
esquerda não existe na direita e então adiciona ele e os filhos dele à lista da
esquerda e segue com o próximo filho da esquerda. Quando os nomes de ambos
os filhos são idênticos, usa-se o método de comparação supracitado quando o
filho é um arquivo, caso o filho seja uma pasta, adentra-se ela em ambos os nós,
ou seja, chama-se a mesma função usando, agora, esses dois filhos. Caso ainda
existam filhos na direita e não exista mais filhos na esquerda, o algoritmo
adiciona todos os demais filhos da direita (e os filhos deles também) à lista da
direita.
4.3.6. União de Árvores
Compara duas árvores e resulta em uma terceira árvore que contém todos
os nós de ambas as árvores comparadas. Caso haja algum conflito, o par de nós
é adicionado a uma lista, identificada como lista de conflitos, e nenhum dos dois
nós é copiado para a árvore resultante.
Essa operação é realizada no processo de sincronia de arquivos, que será
explicado no capítulo 8, e tem como finalidade gerar a árvore com as operações
25
a serem realizadas. Tem comportamento similar à operação de diferença de
árvore, porém não utiliza as informações dos arquivos em todos os casos, mas
utiliza o atributo de modificação em todas as comparações, a Figura 7 ilustra
um exemplo de árvore sendo unida, com base apenas no atributo de modificação.
Figura 7 – Ilustração do processo de união de árvores
Quando um dos nós do par de nós analisado possui nome anterior ao
outro, este nó (e todos os seus filhos) é adicionado à árvore resultante, na
posição equivalente, e segue-se assim como no algoritmo de diferença.
Similar ao processo de diferença de árvores, quando acaba os filhos de um
dos nós, todos os demais filhos do outro nó são adicionados à árvore resultante.
Quando os dois nós do par possuem o mesmo nome, verifica-se o tipo
deles. Caso sejam diferentes, verifica-se se um dos dois nós foi marcado como
deletado, caso nenhum dos dois foi marcado como deletado, esse par de nós é
adicionado à lista de conflitos. Caso ambos os nós sejam pasta, copia o nó para
a árvore resultante e define-se o atributo de modificação como deletado se ao
menos um dos nós estiver marcado como deletado. Caso ambos os nó sejam
arquivos, toma-se a decisão conforme apresentado na Tabela 3.
Devido à forma que as árvores são geradas antes de se executar a
operação de união no processo de sincronia de pastas e arquivos, algumas
situações são impossíveis de ocorrer, mais detalhes podem ser encontrados no
capítulo 8, e por isso nada é feito nessas situações.
Quando o arquivo é criado ou editado em ambas as árvores, o algoritmo
realiza a comparação das informações dos arquivos da mesma forma que no
processo de diferença de árvore, exceto pelo fato de não ignorar o MD5 e, caso o
mesmo não tenha sido calculado, considera-se que é um conflito.
0
1
5
6
8
B
C
3 r
n
n
n
c n
e
0
1
5
6
3 r
r
n
r
0
1
5
6
8
B
C
3 r
r
n
c
c n
4 4
r r
e
26
Nó B criado editado deletado
Nó A criado comparar impossível* impossível*
editado impossível* comparar Nó A deletado impossível* Nó B deletado
Tabela 3 – Decisão entre dois arquivos de mesmo nome
Adicionalmente há uma lista de par de nós para todos os nós que foram
comparados e marcados como iguais durante o processo de união de árvores.
Essa lista é opcional e é usada no processo de sincronia de pastas e arquivos.
4.4. TAREFAS EM SEGUNDO PLANO
Este projeto possui três módulos que necessitam estar operando de forma
contínua e sem interrupção para realizar outras tarefas, são eles:
• Módulo de Interface de Usuário
Módulo responsável por toda a interação do usuário com os demais
módulos que são controláveis. Este módulo não pode ser interrompido por
qualquer tarefa, pois deve dar ao usuário a capacidade de executar ou parar
outras tarefas.
• Módulo do Núcleo de Conectividade
Módulo responsável por receber os pacotes, pela rede, de informação e de
operação. Tais pacotes devem ser tratados assim que chegam e despachar a
tarefa equivalente. Este módulo não pode ser interrompido, pois durante uma
transferência é possível que outros computadores realizem trocas de informações
com este computador que, portanto, deve estar disponível para responder a
essas requisições. Esse módulo será abordado no capítulo 5.
• Módulo de Notificação de Conectividade
Deste módulo, duas operações são desempenhadas, uma verifica as
interfaces de rede e a outra é responsável pelo broadcast que é usado para
notificar que o computador está na rede. Esse módulo também será abordado no
capítulo 5.
27
Como nenhuma das tarefas acima podem ser paradas, foi necessário criar
um módulo para agendar as demais tarefas, como, por exemplo, a tarefa de
transferência de arquivos.
Toda solicitação recebida pelo núcleo de conectividade é previamente
analisada e então dispara a tarefa necessária para processar a solicitação
recebida. Há tarefas que requerem interação com o usuário, não usar tarefa em
segundo plano faria com que dois módulos principais ficassem parados em um
determinado momento.
Toda tarefa é passada ao sistema como tarefa que requer interação com o
usuário ou tarefa automática. A tarefa que requer interação do usuário é
executada pelo módulo de interface do usuário e, por tanto, não deve ter muito
processamento além de simplesmente requisitar alguma informação. Já a tarefa
automática é colocada em uma fila e serão processadas assim que uma das
threads da thread pool estiver disponível.
Essa thread pool é a responsável por manter as tarefas em segundo plano.
Nesse projeto essa thread pool foi limitada a ter apenas duas threads executando
em segundo plano.
Como exemplo, considere o processo de aceitação de um pedido de
criação de canal de sincronia. Ao receber a mensagem de criação de canal de
sincronia, o núcleo de conectividade cria uma tarefa para processar essa
solicitação e coloca essa tarefa como automática. Essa tarefa conecta um socket
com o computador que criou a solicitação, faz um processamento inicial e cria
uma tarefa para perguntar ao usuário se aceita a criação do canal. Essa segunda
tarefa é executada pelo módulo de interface do usuário que deve responder a
solicitação. Ao responder, essa segunda tarefa é finalizada e a primeira tarefa
continua seu processamento. Maiores detalhes sobre esse processo serão
apresentados nos capítulos 7 e 8.
Conforme pode ser visto no exemplo acima, os módulos principais só
interagem com o outro módulo em determinados pontos e com o mínimo de
processamento necessário. Isso permite maior controle para o usuário e melhor
resposta do sistema às requisições realizadas ao computador.
28
4.5. CONCLUSÃO
Os módulos aqui apresentados são de extrema importância para o projeto,
e sem eles o projeto não seria possível da forma que é. Em especial o
ByteStream, que é a base de todas as informações manuseadas no projeto.
Os módulos das próximas seções utilizarão esses módulos e nem sempre
ficará explícito o uso dos mesmos. No próximo capítulo será apresentado o
módulo de conectividade e seus derivados.
29
CAPÍTULO 5
5. CONECTIVIDADE
Neste projeto toda a comunicação entre processos, e consequentemente
entre computadores, é realizada através de mensagens binárias transmitidas por
meio de sockets TCP/IP. Este capítulo abordará a forma como as mensagens
binárias são geradas, o modo como essas mensagens são transmitidas e como
essas mensagens são interpretadas.
A Figura 8 contém os módulos de conectividade e demonstra o
relacionamento entre eles e outros módulos. A seta com linha tracejada indica
que a comunicação é feita por meio da rede.
Figura 8 – Diagrama de relacionamento dos módulos de conectividade
5.1. MENSAGENS DE CONECTIVIDADE
Os módulos de conectividade possuem um único grupo de tipos de
mensagens que podem ser usadas. Essas mensagens são estruturas básicas em C
(struct) que são serializadas em forma binária para serem transmitidas na rede.
Para identificar o tipo de mensagem que foi serializada, o primeiro byte da
mensagem corresponde à identificação da mesma no grupo exclusivo de
mensagens de conectividade.
Por usar apenas um byte, a quantidade máxima de mensagens diferentes
é de 255 (uma vez que o byte nulo é descartado). Entretanto existe um limite
Computador A
Conectividade
Computador B
Conectividade
Núcleo
Notificação
Núcleo
Notificação
Outros módulos
30
imposto de no máximo 127 mensagens diferentes, forçando o bit mais
significativo desse byte em zero. Isso é para permitir que futuramente existam
mais de 255 combinações, usando algum método similar ao adotado no UTF-8.
Abaixo segue a lista de mensagens usadas no projeto, junto com uma
breve explicação de uso e de seus conteúdos. As mensagens estão ordenadas de
acordo com seu byte de identificação. Todas as mensagens que possuem o
prefixo Broadcast podem, e devem, ser enviadas em broadcast. Já as mensagens
que não possuem tal prefixo, não podem ser enviadas em broadcast.
1 - BroadcastHello
Esta mensagem é usada apenas quando o computador entra em uma rede.
Contém o hostname e a identificação única do computador que envia esta
mensagem.
2 - BroadcastHelloExtended
Esta mensagem não é usada, mas já está reservada a sua identificação.
3 - BroadcastIAmHere
Esta mensagem é usada para informar aos demais computadores da rede
que o computador ainda está presente na rede. Contém apenas a identificação
única do computador que envia esta mensagem.
4 - MyCredential
Esta mensagem é usado para informar a identificação do computador.
Contém o hostname e a identificação única do computador que envia esta
mensagem.
5 - MyCredentialExtended
Esta mensagem não é usada, mas já está reservada a sua identificação.
6 - BroadcastConnectionDrop
Esta mensagem é usada para informar que o computador está se
retirando da rede e não contém outra informação adicional, restando aos que
receberem a mensagem, identificarem o peer através do IP de origem da
mensagem.
31
7 - BroadcastCheckHostname
Esta mensagem é usada para pesquisar na rede se existe algum
computador com um determinado hostname, que deve estar contido na
mensagem.
8 - BroadcastCheckHost
Esta mensagem é usada para pesquisar na rede se existe algum
computador com uma determinada identificação única, que deve estar contida
na mensagem.
9 - RequestAddFriend
Esta mensagem é usada para enviar um pedido de solicitação de amizade
a outro computador. Deve conter o hostname e a identificação única do
computador que envia essa mensagem e uma palavra-chave, que será explicada
no capítulo 6.
10 - RequestAddFriendAnswer
Esta mensagem é usada para responder ao pedido de solicitação de
amizade. Deve conter o hostname e a identificação única do computador que
envia essa mensagem e uma palavra-chave, além da devida resposta (sim ou
não).
11 - UpdateFriendCredential
Esta mensagem não é usada, mas já está reservada a sua identificação. É
planejada para atualizar o hostname nos amigos, quando o hostname for
modificado.
12 - RequestAddFriendAck
Esta mensagem é usada para confirmar que a mensagem de pedido de
solicitação de amizade foi recebida pelo computador. Como essas mensagens são
transmitidas por meio de uma conexão UDP, não há garantia de entrega dos
pacotes, portanto a confirmação de entrega deve ser feita “manualmente”. Não
contém nada.
32
13 - RequestAddFriendAnswerAck
Idem à mensagem acima, porém confirma o recebimento da mensagem de
resposta à solicitação de amizade.
14 - RequestChannelTransfer
Esta mensagem é usada para solicitar um canal do tipo transferência de
arquivos entre computadores. Deve conter a porta que será utilizada no canal e
a identificação do canal. Mais informações sobre esse canal serão apresentadas
no capítulo 7.
15 - RequestChannelSync
Esta mensagem é usada para solicitar um canal do tipo sincronia de
pastas e arquivos entre computadores. Deve conter a porta que será utilizada no
canal e a identificação do canal. Mais informações sobre esse canal serão
apresentadas no capítulo 8.
16 - RequestChannelCreater
Esta mensagem é usada para solicitar um módulo de criação de canal
para sincronia de pastas e arquivos entre computadores. Deve conter apenas a
porta que será usada para troca de informações.
5.2. MÓDULO DO NÚCLEO DE CONECTIVIDADE
Responsável por receber as mensagens da rede, decodificar para a
estrutura correspondente, tomar decisão sobre o que fazer com a informação
contida na mensagem e disparar os eventos correspondentes às mensagens
recebidos.
Este módulo possui um socket configurado em UDP para receber pacotes
de qualquer IP em uma porta padrão (4790). Essa configuração permite que o
projeto utilize broadcast para identificar os computadores na rede. Como não há
restrição dos IPs de origem do pacote, ao enviar uma mensagem em broadcast,
o próprio computador recebe a mensagem enviada, nesse caso, este módulo
descarta essa mensagem.
Este módulo permite expandir as operações a serem realizadas com uma
mensagem recebida por meio de uma lista dinâmica que contém a função a ser
33
executada e o tipo de mensagem que deve ter sido recebida para executar a
função associada. Isso permite que outros módulos utilizem o módulo do núcleo
de conectividade para receber determinadas mensagens, como é o caso da
operação de formação de amizade ou a operação de encontrar um computador
na rede. Todavia, as operações padrões implementadas no módulo não podem
ser desativadas, assim sendo, mesmo que uma operação padrão seja expandida,
ela não sobrescreve as operações padrões, nem as demais operações expandidas.
As operações padrões existentes estão associadas ao recebimento das seguintes
mensagens:
1 - BroadcastHello
Ao receber este tipo de mensagem, o módulo de relacionamentos é usado
para verificar se o computador de origem é um amigo. Em caso afirmativo, o
módulo de relacionamentos é notificado que um amigo entrou na rede e o
módulo de notificação de conectividade é informado que deve enviar as próprias
credenciais (MyCredential) para o computador que é amigo.
3 - BroadcastIAmHere
Similar à mensagem acima, porém não utiliza o módulo de notificação de
conectividade.
4 - MyCredential
Idem à mensagem acima.
6 - BroadcastConnectionDrop
Informa o módulo de relacionamentos que o computador associado ao IP
de origem da mensagem não está mais conectado na rede.
7 - BroadcastCheckHostname
Ao receber esta mensagem, compara-se o hostname contido na mensagem
com o hostname que está associado ao computador no programa. Caso sejam
iguais o módulo do núcleo de notificação de conectividade é informado que deve
enviar as próprias credenciais (MyCredential) para o computador que enviou o
broadcast.
34
8 - BroadcastCheckHost
Idem à operação descrita acima, porém comparando a identificação única
do computador.
9 - RequestAddFriend
Ao receber esta mensagem, o módulo de relacionamentos é informado que
uma solicitação de amizade foi criada. O módulo de relacionamentos é que usará
as informações contidas na mensagem para dar continuidade ao processo de
solicitação de amizade.
14 - RequestChannelTransfer
Informa ao módulo de controle de canais que um canal do tipo
transferência de arquivos foi solicitado, incluindo o IP de origem, a porta a ser
usada e a identificação do canal. Indiretamente um módulo de transferência de
arquivos é iniciado com os parâmetros recebidos.
15 - RequestChannelSync
Idem à mensagem acima, porém solicita um canal de sincronia de pastas
e arquivos e, indiretamente, um módulo de sincronia de pastas e arquivos é
iniciado com os parâmetros recebidos.
16 - RequestChannelCreater
Informa ao módulo de controle de canais que há um pedido de criação de
canal de sincronia de pastas e arquivos. Indiretamente um módulo de criação de
canal é iniciado com os parâmetros recebidos.
5.3. MÓDULO DE NOTIFICAÇÃO DE CONECTIVIDADE
Responsável por transmitir todas as mensagens que são usadas pelo
módulo de conectividade, isso cria certo nível de abstração dos demais módulos
em relação ao módulo de conectividade. Também é responsável por enviar a
mensagem de notificação de presença em rede e de identificar as interfaces de
rede e suas alterações em relação à conectividade das mesmas.
A operação de identificação de mudanças nas interfaces de rede e de
notificação de presença precisam ser inicializadas, assim como o núcleo do
módulo de conectividade também precisa ser inicializado. Como estas três
35
operações estão interligadas, todas elas são inicializadas seguindo a ordem:
Verificador de interfaces, Núcleo do módulo de conectividade e, por último, a
Notificação de presença. Cada uma dessas operações possui uma thread que fica
executando em segundo plano, por esse motivo essas operações devem ser
interrompidas ao final do programa.
O verificador de interfaces cria duas listas com as interfaces disponíveis
no sistema (de acordo com o que a API do sistema retorna). Uma das listas
contém o nome da interface (informado pelo sistema), o IP associado à interface,
sendo 0.0.0.0 quando a interface está desconectada, e o IP de broadcast, sendo
0.0.0.0 quando a interface está desconectada. A outra lista possui, além das
mesmas informações da lista citada acima, o MAC Address de cada interface.
Enquanto que a lista com menos informações possui apenas as interfaces que
estão conectadas, a outra lista é mais completa, contendo, também, as interfaces
que não estão conectadas.
A lista contendo apenas as interfaces conectadas é usada na operação de
envio de broadcast, para garantir que a mensagem seja enviada por todas as
interfaces, pois, em testes efetuados durante o desenvolvimento do projeto,
quando um dos computadores possuía mais de uma interface conectada, o
broadcast enviado para o endereço 255.255.255.255 era transmitido por apenas
uma das interfaces. O endereço de broadcast contido na lista é exclusivo para
aquela interface, pois é calculado usando o IP e a máscara da rede a qual a
interface encontra-se conectada.
Essas duas listas são preenchidas assim que a operação de verificação de
interfaces é iniciada e, após isso, esse processo é repetido a cada minuto, até que
o sinal de parada seja enviado para a operação.
A notificação de presença inicia enviando um BroadcastHello, em seguida
entra em um loop em que espera dez minutos e envia um BroadcastIAmHere,
até que o sinal de parada seja enviado ou até que uma solicitação de envio de
credenciais seja efetuado. Neste segundo caso, a espera de dez minutos é
interrompida e uma mensagem de MyCredential é enviado, em unicast, para o
IP contido na lista de IPs a enviar as credenciais (que corresponde aos IPs que
outros módulos solicitaram para enviar as credenciais), em seguida retorna-se ao
loop normal (espera e envio de BroadcastIAmHere). Quando o sinal de parada é
enviado, a mensagem BroadcastConnectionDrop é automaticamente enviado.
36
Além dessas duas operações citadas, o módulo de notificação de
conectividade possui funções para o envio de cada um dos tipos de mensagens
disponíveis no núcleo de conectividade. O argumento dessas funções corresponde
às informações que devem estar contidas nas respectivas mensagens. Com
exceção da função de envio da mensagem de BroadcastCheckHostname, todas as
demais mensagens são enviadas em unicast e, por isso, o primeiro argumento da
função é o IP de destino.
5.4. CONSIDERAÇÕES
Os módulos de conectividade possuem seus próprios métodos de operação
interna e foram feitos para operar de forma autônoma e responsiva, disparando
tarefas ou acionando callbacks referentes às mensagens recebidas que foram
enviados por outro computador através do outro módulo de conectividade,
mantendo, assim, uniformidade no conteúdo que circula nesse meio.
Nas implementações mais recentes, por exemplo, os canais (de
transferência ou sincronia), este módulo só é utilizado para formar uma conexão
TCP entre os computadores envolvidos, porém o módulo ainda permite que
outras operações sejam realizadas sem a necessidade do uso de outra conexão,
que é o caso da operação de formação de amizade, que será descrito no próximo
capítulo, onde se utiliza o recurso de callback para receber as respostas da
solicitação.
37
CAPÍTULO 6
6. RELACIONAMENTOS
Os módulos deste capítulo são responsáveis pelas informações de cada
computador com o qual o computador host possui vínculo, que é chamado de
“amizade” neste projeto, no que diz respeito a armazenar essas informações,
gerenciar essas informações (incluindo o processo de formar amizade), identificar
um computador na rede e validar as credenciais dos computadores para verificar
a autenticidade da amizade.
Ao longo deste capítulo, esses módulos serão explicados quanto a sua
funcionalidade e operabilidade, assim como os casos de uso dos mesmos. Porém,
antes de explicar os módulos, é necessário abordar sobre as informações que
caracterizam um amigo.
6.1. AMIGO
Amigo é uma forma de chamar o computador (peer) que possui um
relacionamento estabelecido com o computador host. No escopo do projeto,
amigo é uma estrutura que armazena as informações referentes ao computador
(peer) e a essa amizade, afinal, não há motivos para armazenar uma cópia de
qualquer outro computador na rede (e que possua o projeto em execução) sendo
que esse não possui relações com o computador host.
Essa estrutura armazena a identificação do amigo dentro do banco de
dados (que é usado em outros módulos que requerem essa identificação), a
identificação única do amigo (que é diferente da identificação do banco de
dados), o hostname do amigo, o IP do amigo, as duas chaves de segurança
formadas com o amigo e a data e hora da última mensagem recebida do amigo.
Todas essas informações ficam armazenadas em uma tabela no banco de
dados. O uso de uma chave de identificação interna diferente da identificação
única é para evitar possíveis conflitos num futuro caso haja mudança no método
38
de se obter identificação única. Ao abrir o banco de dados o IP de todos os
amigos são definidos como 0.0.0.0 e a data e hora da última mensagem recebida
é zerada. Assim sendo, um amigo só é considerado online quando o IP for
diferente de 0.0.0.0 e a data e hora da última mensagem recebida não for
anterior a quinze minutos em relação à data e hora atual.
Figura 9 – Diagrama de relacionamento dos módulos de relacionamento
6.2. MÓDULO DO NÚCLEO DE RELACIONAMENTOS
Conforme pode ser observado no diagrama da Figura 9, este módulo é
responsável por todas as operações que envolvem o banco de dados e, desta
forma, oferece funções que permitem acessar os elementos do banco de dados, da
tabela de relacionamentos, além de possuir funções únicas que disparam outras
tarefas dentro do programa.
É importante ressaltar que existe uma restrição em relação ao tempo de
vida do resultado das consultas ao banco de dados, pois esses resultados são
uma cópia do conteúdo do banco de dados, e não são atualizadas
dinamicamente, sendo necessária uma nova consulta para atualizar os dados.
Além de que todo o projeto foi criado para funcionar de forma assíncrona, assim
sendo, é possível que a informação seja modificada no banco de dados logo após
ela ter sido consultada, como é o caso de quando se recebe BroadcastHello ou
BroadcastIAmHere, em que a informação de IP e última data e hora de
recebimento de mensagem são atualizados. Pensando nisso, toda consulta
realizada no projeto é usada de imediato.
Existem, neste módulo, sete funções que processam diretamente sobre o
banco de dados: Uma operação para adicionar um amigo ao banco de dados,
uma operação de atualizar as informações de um amigo no banco de dados, uma
função que preenche um array com todos os amigos do banco de dados, e quatro
Relacionamento
Núcleo BD
Conectividade
Núcleo
Notificação
Formação
Procura Validação
39
funções que retornam um amigo com base em uma consulta, que pode ser a
identificação única, o IP, o hostname ou a identificação interna. Com exceção
das funções de consulta, as demais funções de acesso direto ao banco de dados
devem ser evitadas, procurando utilizar alguma outra função do módulo que
realize este trabalho.
A fim de reduzir o uso de recursos, existe uma função que apenas verifica
se existe um amigo com uma determinada identificação única no banco de dados,
onde, ao invés de copiar todas as informações do amigo do banco de dados para
a estrutura em memória, é feito uma simples consulta ao banco de dados para
verificar se o amigo existe, retornando verdadeiro ou falso. Utilizado pelo núcleo
de conectividade quando recebe um BroadcastHello.
Também usado pelo núcleo de conectividade, tanto quando recebe um
BroadcastHello, quanto ao receber um BroadcastIAmHere ou um MyCredential,
é a função de notificação de presença. Ela é responsável por atualizar no banco
de dados o IP do amigo e a data e hora que foi executada, além de agendar uma
tarefa de sincronia de pastas e arquivos com o amigo, caso haja algum canal de
sincronia de pastas e arquivos estabelecido entre eles. Assim como existe a
função que atualiza quando um amigo está online, existe a função que atualiza o
banco de dados quando o amigo envia uma mensagem de
BroadcastConnectionDrop. É importante ressaltar que um amigo é marcado
como off-line não apenas após receber um BroadcastConnectionDrop dele, mas
quando a data e hora da última atualização de IP recebida for superior a 15
minutos.
A priori o processo de formar amizade entre dois computadores era
realizado por este módulo, mas, devido à complexidade que o algoritmo iria
atingir, um módulo específico para este processo foi criado, conforme será
apresentado adiante.
6.3. MÓDULO DE FORMAÇÃO DE AMIZADE
Este módulo é responsável pelo processo de formação de amizade entre
dois computadores pela rede. É dividido em duas grandes partes, onde uma é
responsável por enviar o pedido de amizade e a outra é responsável por
responder.
40
Enquanto a solicitação é feita através de uma classe, que efetua todos os
procedimentos de solicitação, a resposta é efetuada por meio de uma tarefa. Isso
permite que a tarefa de resposta seja realizada pelo usuário ou de forma
automática, onde esta segunda ocorre quando o peer recebe uma solicitação de
amizade de outro peer que já está definido como amigo, neste caso a tarefa é
automaticamente executada como resposta positiva. Além de permitir, no futuro,
a implementação de uma lista negra para solicitações de amizade.
As trocas de mensagens realizadas entre os computadores durante o
processo de solicitação de amizade segue o padrão ilustrado no fluxograma da
Figura 10, onde o fluxo da esquerda pertence ao peer que efetua a solicitação do
pedido de amizade e a seta tracejada simboliza o pacote transmitido através da
rede.
Neste módulo, toda operação de envio de mensagem é realizada pelo
módulo de notificação de conectividade, conforme pode ser observado no
diagrama da Figura 9, assim como toda mensagem é recebida pelo módulo do
núcleo de conectividade, através do recurso de expansão de operações que o
módulo possui.
Figura 10 – Fluxograma da solicitação de amizade
A classe que implementa o processo de envio da solicitação de amizade
possui uma máquina de estados interna que controla todo o processo. A função
da classe que realiza o processamento da máquina de estados deve sempre ser
Envia
Solicitação
Recebe
ACK
Recebe Resposta
Envia ACK
Recebe
Solicitação
Envia ACK
Obtém Resposta
Envia Resposta
Recebe ACK
41
chamada enquanto o retorno da função solicitar para ser executada novamente,
justamente devido à existência da máquina de estados interna.
Ao iniciar a máquina de estados, dois callbacks são registrados no módulo
do núcleo de conectividade, um para quando recebe o ACK (Acknowledgement)
e outro para quando recebe a resposta, e então a solicitação é enviada para o
peer e mantém-se em um estado esperando pelo ACK correspondente. Caso o
ACK não seja recebido dentro de um tempo limite de dez segundos, a operação
é finalizada com erro. Após receber o ACK, espera-se a resposta por até cinco
minutos, falhando após esse tempo sem receber a resposta.
Devido ao uso do UDP, é possível que a resposta seja recebida sem que
tenha recebido o ACK, nesse caso o processo pula direto para o estado seguinte
ao que espera pela resposta. Após receber a resposta, três ACKs são enviados
em sequência para o peer e a máquina de estados entra em seu estado final, e a
função passa a retornar a resposta da solicitação.
Do outro lado, quando o módulo do núcleo de conectividade recebe uma
mensagem de solicitação de amizade, é acionado, no módulo aqui descrito, o
procedimento de resposta à solicitação de amizade, que consiste em criar uma
tarefa do tipo TaskUserFriendRequestResponse e atribuir essa tarefa à lista de
tarefas que requer interação com o usuário ou à lista com processamento
automático, caso o peer já seja amigo.
Ao criar a tarefa supracitada, um ACK é enviado para o peer,
informando que recebeu o pedido de solicitação de amizade, e a tarefa é
escalonada como uma tarefa de interação com o usuário ou como uma tarefa
automática se, e somente se, o peer já for um amigo. Após registrar a tarefa,
tem-se até cinco minutos para responder à tarefa, após esse tempo a tarefa é
invalidada e todo o processo de solicitação de amizade é encerrado.
Responder a tarefa corresponde em responder à solicitação de amizade,
sendo assim, é necessário informar se aceita ou não o pedido. Para ambas as
respostas, a mensagem contendo a resposta é enviada ao peer. E aguarda-se o
peer responder com um ACK, enquanto isso não ocorre, a resposta é reenviada a
cada cem milésimos de segundo durante o intervalo de cinco segundos.
As chaves usadas podem ser definidas manualmente ou automaticamente.
Caso as chaves não tenham sido definidas até o momento em que se envia o
42
pedido ou se envia a resposta, o módulo gera uma chave aleatória com 24
caracteres.
6.4. MÓDULO DE PROCURA DE PEER
Este módulo permite achar um peer na rede através de seu hostname ou
de sua identificação única, através do recurso nativo do módulo do núcleo de
conectividade de responder às mensagens de BroadcastCheckHostname e
BroadcastCheckHost.
Similar à classe do módulo de formação de amizade, este módulo registra
um callback no módulo do núcleo de conectividade para cada mensagem do tipo
MyCredential recebido. Quando tal tipo de mensagem é recebido, o hostname ou
a identificação única é conferido para averiguar se corresponde a uma resposta
do broadcast enviado. Também implementa uma máquina de estados interna e
requer que a função de processamento seja executada de tempos em tempos,
recomendável que seja algo menor ou igual a um segundo.
Quando se realiza a procura pela identificação única, a operação é
encerrada assim que o primeiro peer responder com a mesma identificação única
solicitada. Caso não haja resposta em até trinta segundos, é caracterizado que
não há um peer com aquela identificação única na rede. Durante esse tempo em
que a operação é executada, a cada dois segundos uma mensagem de
BroadcastCheckHost é enviado.
A procura pelo hostname é similar à procura pela identificação única,
espera-se até trinta segundos pela resposta de algum peer, enviando a mensagem
BroadcastCheckHostname a cada dois segundos. Porém, quando recebe uma
resposta válida, o peer que respondeu entra em uma lista e o processo só é
encerrado após oito segundos após receber a primeira resposta.
Após a conclusão do processo de procura, seja com sucesso ou sem
resposta, deve-se extrair do módulo a lista dos peers que responderam. Assim
sendo, com base no número de peers nessa lista, pode-se concluir se a busca não
encontrou nenhum peer, ou seja, a lista está vazia, ou se a busca encontrou um
ou mais peers, sendo que a busca por identificação única nunca terá mais de um
peer na lista.
43
6.5. MÓDULO DE VALIDAÇÃO DE AMIZADE
Este módulo é responsável por usar as chaves definidas na amizade entre
os peers para verificar se dois peers são realmente amigos em uma conexão TCP
já estabelecida. Seu funcionamento é similar a um aperto de mãos, o que dá o
nome do módulo (handshake).
Existe uma função única que codifica uma string em outra, seguindo um
padrão interno, de forma que a mesma string de entrada sempre gera a mesma
string de saída. Esse conceito é a base do processo de handshake, conforme pode
ser observado no fluxograma da Figura 11, onde uma mesma mensagem é
enviada para outro computador, a mesma codificação é realizada e a mensagem
resultante é igual.
Figura 11 – Fluxograma do conceito básico do handshake
A fim de garantir que os peers são amigos, as mensagens são
criptografadas antes de serem transmitidas, usando as chaves que ambos peers
possuem. Note que uma das chaves foi gerada/definida por um dos peers e a
outra foi gerada/definida pelo outro peer, assim sendo, chamar uma chave de
“sua”, significa que é a chave que foi gerada/definida por esse peer.
No processo de handshake, conforme pode ser visto no fluxograma da
Figura 12, um dos peers inicia gerando a mensagem, criptografa a mensagem,
usando a sua chave, e envia para o outro peer, que deve decodificar usando a
chave do amigo, aplicar a função de codificação, criptografar usando a sua chave
e transmitir de volta para o outro peer. Eis que o primeiro peer descriptografa a
mensagem recebida e compara idem ao processo descrito acima.
Mensagem
Original
Codifica Mensagem
Mensagem Codificada
Compara
Mensagem Original
Codifica Mensagem
Mensagem Codificada
44
Após a comparação, um ACK é enviado, contendo um byte informando se
ambos os peers realmente são amigos e o processo de handshake é encerrado em
ambos os lados. É fácil notar que a transmissão de dados pelo socket pode falhar,
o módulo possui tolerância a até três falhas na transmissão, incluindo timeout,
mais erros que isso, a operação é encerrada com o código de erro do socket.
Figura 12 – Fluxograma principal do handshake
6.6. OBSERVAÇÕES
Tanto o módulo de formação de amizade quanto o módulo de procura de
peer utilizam os sockets do módulo do núcleo de conectividade e do módulo de
notificação de conectividade. Porém, o módulo de validação de amizade utiliza
um socket TCP, que já esteja conectado, para realizar a verificação.
É importante ressaltar que a estrutura obtida nas funções de consulta de
amizade no banco de dados é uma cópia do conteúdo do banco de dados no
momento da consulta, e tais valores não devem ser considerados vitalícios, pois
algum outro módulo pode modificar o banco de dados de forma assíncrona.
A estrutura de amigo contém a identificação do mesmo dentro do banco
de dados. Tal valor deve ser usado apenas para relacionamento entre tabelas no
banco de dados, uma vez que é este valor que é usado nas tabelas de canal de
transferência e canal de sincronia, que serão apresentadas adiante.
Mensagem
Original
Codifica Mensagem
Mensagem Codificada
Compara
Mensagem Original
Codifica Mensagem
Mensagem Codificada
encrypt key 1
decrypt key 1
encrypt key 2
decrypt key 2
45
CAPÍTULO 7
7. TRANSFERÊNCIA DE ARQUIVOS
Embora já tenha sido apresentado o módulo que realiza transferência de
dados entre dois computadores (o DataStreamer, no capítulo 4), este realiza
apenas esta função, sem nenhum controle ou conhecimento do tipo de dado que
é transferido, por isso existe a necessidade de um módulo capaz de gerenciar e
controlar o uso do DataStreamer para, efetivamente, realizar uma transferência
de arquivo.
Figura 13 – Diagrama de relacionamento do módulo de transferência de arquivos
O módulo de transferência de arquivos compartilha algumas
características com o módulo de sincronia, o modo como a conexão é
estabelecida, o modo como as mensagens são transmitidas, ambos possuem um
socket de controle e usam o DataStreamer. Tais características, juntas, formam
o Canal de Transmissão.
7.1. O CANAL E SUAS CARACTERÍSTICAS
Este conceito de canal é utilizado para permitir a existência de
personalização de transferências, por exemplo, modificar a pasta de destino de
um determinado canal, bloquear a transferência de arquivos de canais não
Transferência
Socket Conectividade
Notificação DataStreamer
Controle
ByteStream
Relacionamento
Núcleo BD
46
configurados, entre outros, além de permitir o uso de uma mesma
implementação em ambos os canais, por exemplo, o handshake.
Todo canal de transferência de arquivo possui uma identificação única, só
pode estar associado a um amigo apenas, um nome definido pelo usuário, um
path padrão para onde todos os arquivos transferidos serão armazenados, e uma
opção para aceitar automaticamente transferências nesse canal.
A identificação única é tal que nenhum dos dois peers envolvidos possui
outro canal com a mesma identificação, portanto, em uma rede com quatro, ou
mais, peers é possível que existam dois canais de transferência de arquivos com
a mesma identificação, porém envolvendo peers diferentes.
O canal de transferência de arquivos mantém a estrutura de pastas da
origem no destino, portanto, antes de transferir arquivos é necessário
transformar o path real dos arquivos em um path relativo. Deve-se definir até
que parte do path real deve ser ignorado, para definir o path relativo. Uma
simples cópia de arquivo deve ignorar todo o path real.
O path relativo é transformado em path real usando o path definido para
aquele canal, caso o campo esteja em branco, ou a transferência não esteja sob
um canal identificado, o path do amigo é que será utilizado. A Figura 14 ilustra
as operações com o path de um arquivo em uma transferência de arquivos. É
válido lembrar que todas as operações internas utilizam o padrão Unix na
notação de pastas e arquivos.
Figura 14 – Diagrama de remoção e adição de path na transferência de arquivos
Remove path J:\swap\
J:\swap\TCC\imagem.png
TCC/imagem.png
/home/dig Adiciona path
/home/dig/TCC/imagem.png
47
Após preencher a lista com o endereço de todos os arquivos a serem
transferidos, pode-se usar a função auxiliar que detectará qual parte do path de
cada arquivo é comum entre eles para, então, usar como a parte do path a
ignorar. O processo de conexão só pode ser iniciado após definir o IP de destino,
os arquivos a transmitir e a parte do path a ser removida. Note que não é
obrigatório informar o canal a ser utilizado, nem é necessário que o IP de
destino seja um amigo.
7.2. ESTABELECENDO A CONEXÃO ENTRE OS PEERS
O processo de transferência de arquivos é efetuado em apenas um sentido,
portanto, aquele que inicia a transferência e consequentemente possui os
arquivos a transmitir, é chamado de servidor, enquanto que o destinatário é
chamado de cliente.
Uma vez iniciado o processo de transferência pelo servidor, o módulo
requisita uma porta TCP para o módulo do núcleo de conectividade, tal porta é
usada pelo socket de controle do módulo, que é colocado no modo ouvinte para
aguardar a conexão do cliente. Após abrir a porta, o módulo envia um
RequestChannelTransfer contendo a porta em que o servidor está ouvindo e a
identificação única do canal. Caso a identificação única do canal não esteja
definida, tal campo será enviado em branco.
Após ter sido estabelecido a conexão, o servidor envia suas próprias
credenciais, pelo socket de controle, e aguarda a resposta do cliente com as
credenciais do mesmo. Caso os peers sejam amigos, inicia-se o processo de
handshake, caso contrário, envia-se o pedido. Se houver um canal definido e os
peers não sejam amigos ou o cliente não seja o amigo associado ao canal, a
operação é cancelada. A Figura 15 contém o fluxograma dessas operações
realizadas no servidor durante o processo de conexão.
De forma complementar ao processo de conexão do servidor, o processo
de conexão do cliente, que pode ser observado no fluxograma da Figura 16,
inicia com o recebimento do broadcast pelo módulo do núcleo de conectividade,
que cria a tarefa associada à transferência. Tal tarefa conecta à porta informada
e troca credenciais com o servidor. De acordo com a resposta do servidor, o
cliente pode encerrar a operação, realizar o handshake ou ir direto para o pedido
de transferência.
48
Figura 15 – Fluxograma de conexão do servidor
Ao receber o pedido, verifica-se se o canal está definido e possui a opção
de aceitar automaticamente ativa. Caso contrário, cria-se uma tarefa de
interação com o usuário, perguntando se o mesmo aceita a transferência,
enviando a resposta ao servidor. Após enviar a resposta, inicia-se o processo de
transferência de arquivos, caso a resposta seja positiva.
Assim que se chega ao estado de iniciar o processo de transferência, o
DataStreamer é conectado, onde, mais uma vez, o servidor é responsável por
ouvir uma porta, enquanto que o cliente é que conecta a essa porta. Assim que o
DataStreamer entra no modo ouvinte, o servidor envia uma mensagem ao
Abre socket
Envia
Broadcast
Conexão
Estabelecida
Troca Credenciais
Amigos? Realiza Handshake
Canal?
Envia Pedido
Encerra
Processo
Sim
Sim
Não
Não
Aceita? Não
Inicia Transferência Sim
49
cliente informando a porta do DataStreamer. Estabelecido a conexão do
DataStreamer, inicia-se o processo de transferência.
Os dois sockets que são abertos e conectados nessa etapa, são mantidos
conectados até o fim da transferência dos arquivos.
7.3. TRANSFERINDO ARQUIVOS
Nesta etapa, o servidor itera a lista de arquivos marcados para enviar.
Abre-se cada arquivo com um ByteStream do tipo arquivo, no modo somente
leitura. Segue-se enviando uma mensagem informando o nome do arquivo com o
path relativo e o tamanho do arquivo. E utiliza o DataStreamer para enviar o
conteúdo do arquivo.
Figura 16 – Fluxograma de conexão do cliente
Recebe Broadcast
Estabelece Conexão
Recebe Pedido
Handshake
Realiza
Handshake
Processa Pedido
Envia Resposta
Inicia Transferência
Aceitou? Encerra Processo
Núcleo de Conectividade
Não
Sim
50
Do lado do cliente, aguarda-se a mensagem, que pode ser informando o
final do processo ou informando que um arquivo será transferido. Ao receber a
mensagem de arquivo a receber, cria-se um arquivo com o ByteStream para
arquivo com escrita assíncrona, usando o nome do arquivo com path relativo
recebido na mensagem, acrescido do path real, conforme apresentado no
diagrama da Figura 14. Utiliza-se o DataStreamer para receber o conteúdo do
arquivo.
O DataStreamer realiza a transferência de todo o conteúdo do arquivo.
Em caso de falha o DataStreamer retorna o erro equivalente e, no cliente, o
arquivo criado é apagado, enquanto que no servidor é feito até três tentativas de
envio. Em caso de falha em todas as tentativas, a operação é cancelada.
7.4. FINALIZANDO O PROCESSO E CONCLUSÕES
Uma vez terminado a transferência de todos os arquivos, o servidor envia
a mensagem de término para o cliente e informa que a transferência foi
concluída com sucesso. O cliente, que já estava esperando alguma mensagem, ao
receber a mensagem de término, encerra a tarefa que estava associada ao
processo de transferência.
O processo de transferência de arquivos é muito simples ao considerar
que a transferência dos dados na rede está a cargo de outro módulo
especializado nessa operação. Entretanto sua simplicidade é a chave para
permitir reusar a implementação de transferência de arquivo no processo de
sincronia de pastas e arquivos.
51
CAPÍTULO 8
8. SINCRONIA DE PASTAS E ARQUIVOS
Embora a essência pareça similar ao do processo de transferência de
arquivos, inclusive a estrutura deste módulo é similar à estrutura do módulo de
transferência de arquivos, o processo de sincronia de pastas e arquivos possui
algumas diferenças, dentre elas a própria característica de assegurar que toda a
estrutura de pastas e arquivos esteja idêntica em ambos os computadores e a
necessidade de um existir um canal configurado.
O processo de sincronia possui uma etapa que pode ser realizada antes de
se estabelecer uma conexão entre os computadores, que é a etapa de verificação
de diferença, pois caso não haja nenhuma alteração na estrutura (ou conteúdo)
de pastas e arquivos, não é necessário estabelecer conexão com o outro peer.
Abaixo está explicado o porquê dessa não necessidade de conexão para verificar
se há diferença.
8.1. O CANAL E SUAS CARACTERÍSTICAS
Todas as informações armazenadas no canal de transferência de arquivos,
também são armazenadas no canal de sincronia de pastas e arquivos, porém,
enquanto que o path é opcional no canal de transferência de arquivos, no canal
de sincronia o path é obrigatório. A data e hora da última execução do processo
de sincronia é também armazenada para evitar execução do processo de
sincronia quando o relógio do computador está atrasado, e permitir configurar
um intervalo mínimo entre a execução do mesmo processo de sincronia.
Outra informação armazenada é a árvore de pastas e arquivos da última
sincronia realizada. Após terminar o processo de sincronia, a árvore que é
armazenada no banco de dados é atualizada contendo as modificações realizadas
com sucesso durante o processo de sincronia. Assim sendo, após terminar o
processo de sincronia, ambos os computadores possuem a mesma árvore
52
armazenada em seu banco de dados. Por isso não é necessário estabelecer
conexão para verificar se há alteração.
A data e hora de criação ou modificação do arquivo não são sincronizadas
entre os computadores. Essa foi uma medida tomada para evitar que possam
existir arquivos com data e hora de criação/modificação futura em relação à
data e hora do computador, e, ao mesmo tempo, contorna eventuais problemas
envolvendo data e hora e fuso horário, assim como evita problema com
computadores com data e hora errados.
Embora a data e hora de modificação não sejam sincronizadas, elas são
utilizadas, juntamente com o tamanho do arquivo, para decidir se o arquivo não
foi alterado ou se ele foi modificado. Caso apenas a data do arquivo tenha sido
modificada, o algoritmo coloca o arquivo em uma lista para verificar o hash do
mesmo e marcar o arquivo como não modificado ou como modificado. Caso o
tamanho do arquivo tenha sido alterado, o arquivo é marcado como modificado.
Essas marcações serão mais bem detalhadas a seguir.
O processo de sincronia é bidirecional, ou seja, ambos podem enviar e
receber arquivos, e, nessas condições, o nome servidor é designado ao
computador que realiza todo o processamento das árvores e das tomadas de
decisões, enviando, para o cliente, quais operações serão realizadas, e com quais
arquivos e/ou pastas. No geral, servidor é o primeiro a enviar a mensagem de
solicitação de canal de sincronia.
8.2. A DETECÇÃO DE DIFERENÇAS
Conforme mencionado anteriormente, o processo de sincronia só conecta
após verificar se há diferença entre a estrutura de pastas e arquivos no
computador, com a cópia da estrutura de pastas e arquivos que existia após o
último processo de sincronia.
Assim que o processo é iniciado, obtém-se, do banco de dados, a
estrutura de pastas e arquivos resultantes do último processo de sincronia (caso
não exista um último processo de sincronia, a estrutura estará vazia) e é
montada a DirTree dessa estrutura, sendo que a estrutura está serializada em
JSON no banco de dados. Essa estrutura será chamada de estrutura base e é,
com exceção da data de modificação, idêntica à estrutura contida no banco de
dados do outro computador.
53
Após importar a estrutura do banco de dados, é criado uma DirTree
simples, ou seja, sem o hash dos arquivos, da pasta definida como path do canal.
Assim temos duas árvores, uma correspondente à última sincronia e a outra
corresponde ao estado atual das pastas e arquivos.
Com as duas árvores montadas, realiza-se o processo de diferença sem
hash da própria DirTree. (Ignorar o hash faz com que o processo de diferença
marque todos os arquivos que tiverem a data e hora ou o tamanho modificados.)
O resultado dessa diferença são três listas, uma contendo as pastas e arquivos
que foram apagados, outra contendo as pastas e arquivos que foram criados e
outra contendo os arquivos que foram modificados.
Devido ao uso da diferença da árvore sem o uso do hash, é possível que
existam arquivos que foram marcados como modificados (apenas pela diferença
da data e hora de modificação), mas possuem o mesmo tamanho e o mesmo
conteúdo, ou seja, é o mesmo arquivo, mas que teve a data e hora de
modificação alterada. Por esse motivo, para todos os arquivos marcados como
modificados e que possuem o mesmo tamanho, é calculado e comparado o hash
desses arquivos. Caso o hash dos arquivos sejam iguais (o do arquivo da árvore
base com o do arquivo da árvore nova), o arquivo é removido da lista e a
informação do arquivo na árvore base é atualizada, também um flag é acionado
para atualizar o banco de dados.
Caso, neste ponto, todas as três listas estejam vazias, o banco de dados é
atualizado com a data e hora atual, caso o flag citado acima esteja marcado, a
árvore base é serializada e salva no banco de dados. Caso contrário, inicia-se o
processo de estabelecer conexão.
8.3. ESTABELECENDO CONEXÃO ENTRE OS PEERS
O estabelecimento da conexão do processo de sincronia tem a essência
similar ao do processo de transferência de arquivos. Logo após o servidor
terminar o processo de detecção de diferenças, inicia-se o estabelecimento da
conexão, conforme pode ser acompanhado na Figura 17.
O servidor solicita duas portas TCP ao núcleo de conectividade, e abre
um socket no modo ouvinte. Através do módulo de notificação de conectividade,
até quatro RequestChannelSync são enviados (uma mensagem a cada três
segundos, durante o intervalo de doze segundos) para o IP do amigo. Uma vez
54
conectado, o servidor realiza o handshake com o cliente, seguindo por informar
(pelo servidor) a porta em que o DataStreamer está ouvindo. Assim que a
conexão do DataStreamer é estabelecida, inicia-se o processo de sincronia.
Figura 17 – Fluxograma de conexão do processo de sincronia do servidor.
Observe que dois sockets são abertos, mas são conectados em momentos
diferentes, sendo que o socket de controle é o primeiro a ser conectado. Qualquer
erro em qualquer parte do processo de estabelecimento da conexão resulta no
cancelamento completo do processo de sincronia.
As etapas de conexão do cliente são complementares às do servidor, com
o grande diferencial em que o gerenciador de canais de sincronia pode iniciar um
processo (do zero) de sincronia para o canal desejado, ou converter o canal de
sincronia que foi aberto como servidor para o modo cliente. Tal conversão só
pode ocorrer enquanto o canal está montando as árvores, assim que o módulo
inicia a etapa de conexão, é impossível converter o modo dele.
Abre sockets
Envia
Broadcast
Conexão
Estabelecida*
Realiza Handshake
Envia porta DataStreamer
Conecta
DataStreamer
Inicia Sincronia
55
A conversão de modo foi criada devido à possibilidade do processo de
sincronia do mesmo canal ser inicializado simultaneamente em cada um dos dois
computadores. A fim de reduzir a chance de isso ocorrer, adota-se um tempo
aleatório (cerca de um a cinco minutos) para iniciar o processo de sincronia
quando o módulo do núcleo de relacionamentos detecta que o amigo ingressou
na rede. Entretanto, mesmo com esse tempo, ainda é possível que os processos
sejam executados simultaneamente, devido ao poder de processamento dos
computadores por exemplo.
A conversão de modo visa aproveitar as informações já processadas no
modo servidor, incluindo as árvores montadas, de forma a não precisar repetir
essas etapas no modo cliente.
8.4. OPERAÇÕES DO MODO CLIENTE
O modo cliente é basicamente um modo escravo. Não possui nenhuma
tomada de decisão, apenas realiza as operações solicitadas pelo servidor.
Assim que a conexão é estabelecida, o servidor solicita a árvore de
diferença do cliente (árvore montada com o resultado da diferença entre a
árvore atual e a árvore base do cliente, incluindo flags que marcam se a
pasta/arquivo foi criado, modificado ou removido). Quando se realiza a
conversão de modo, a tarefa do modo cliente espera a tarefa do modo servidor
terminar de montar a árvore de diferença (momento em que a tarefa do modo
servidor é encerrada devido à conversão).
Existem momentos em que o computador está esperando algum processo
paralelo terminar ou está esperando uma mensagem do outro computador.
Durante esses momentos, fica-se enviando uma mensagem informando que a
conexão ainda está estabelecida e que o computador está operando. Esta atitude
foi tomada a fim de evitar a possibilidade do socket de controle entrar em um
estado indefinido devido à queda de conexão entre os computadores.
Toda pasta criada ou removida, todo arquivo recebido do servidor (criado
ou modificado), todo arquivo enviado com sucesso para o servidor e todo
arquivo removido, são adicionados, modificados ou removidos da árvore base,
contendo a informação de data e hora de modificação dos arquivos locais. Ao
terminar o processo do modo cliente com sucesso, ou seja, ao receber a
56
mensagem de finalização do servidor, a árvore base é salva no banco de dados,
junto com a data e hora atual do computador.
8.5. OPERAÇÕES DO MODO SERVIDOR
O computador que opera neste modo é responsável por processar as
árvores de diferenças, gerar as decisões a serem tomadas com cada pasta e
arquivo, e controlar e notificar as operações a serem realizadas pelo cliente.
Figura 18 – Diagrama de operações do modo servidor
Conforme pode ser acompanhado no diagrama da Figura 18, após o
módulo iniciar o modo servidor (após estabelecer a conexão), o servidor solicita
Obtém
Diferença
Une as
Diferenças
Remove Pasta/Arquivo
Cria Pastas
Envia Arquivos
Recebe Arquivos
Calcula Diferença
Informa
Igualdades
57
ao cliente a árvore de diferenças do cliente. De posse de ambas as árvores de
diferença, a lembrar que a árvore do servidor já está montada, o servidor une as
duas árvores, a fim de gerar a árvore que contém todas as operações a serem
realizadas.
Ambas as árvores de diferença possuem os flags que denotam se o arquivo
ou pasta foi criado, modificado ou removido. O processo de união das árvores de
diferença é realizado pelo próprio DirTree e resulta em uma árvore, uma lista de
conflitos e uma lista de igualdades. Neste primeiro momento, a árvore de
diferenças do cliente não possui o hash dos arquivos, portanto, caso a lista de
conflitos não esteja vazia, o servidor solicita que o cliente calcule o hash desses
arquivos em conflito, e, em paralelo, o servidor calcula o hash dos mesmos
arquivos, caso não esteja calculado.
Estando com ambas as árvores de diferença com o hash calculado dos
arquivos com conflitos, tanto pelo servidor quanto pelo cliente, a operação de
união de árvores é executada novamente. Caso ainda haja conflitos, esses
conflitos são ignorados, ou seja, o conteúdo dos arquivos não serão modificados e
estes arquivos não serão adicionados no banco de dados.
Caso a lista de arquivos iguais não esteja vazia, o servidor envia essa lista
para o cliente, e ambos atualizam suas próprias árvores base para esses arquivos.
Isso é realizado, pois não há necessidade de transmitir os arquivos sendo que
eles são idênticos (com base no hash e no tamanho).
Uma vez obtido a árvore final de todas as diferenças (resultado da união),
obtém-se, calculando a diferença entre a árvore final e as árvores de diferença,
as operações que devem ser realizadas por cada computador. Ou seja, ao obter a
diferença entre a árvore final e a árvore de diferença do servidor, obtém-se a
árvore que corresponde às modificações necessárias no servidor, chamada de
árvore de diferença real (do servidor). E o mesmo é obtido para o cliente,
usando a árvore de diferença do cliente.
De posse das árvores de diferença real (tanto do servidor quanto do
cliente), obtém-se a lista de pastas e arquivos a serem removidos. Envia-se a
lista do cliente para o mesmo, ao passo que, em paralelo, executa a remoção dos
arquivos e pastas (no servidor) seguindo a lista de remoção do servidor. Após
ambos os computadores terminarem a remoção, segue-se com o processo de
criação de pastas, que é similar ao processo de remoção de pastas e arquivos,
58
porém para criar pastas (apenas). Essa ordem foi escolhida por evitar o
problema de tentar criar uma pasta com o mesmo nome de um arquivo (que foi
removido), e vice-versa.
Após a conclusão das etapas preliminares, inicia-se a transferência de
arquivos do servidor para o cliente, com base nos arquivos contidos na árvore de
diferença real do cliente. Uma vez terminado de enviar os arquivos, o servidor
solicita que o cliente envie os arquivos que estão contidos na árvore de diferença
real do servidor.
Idem ao que ocorre no modo cliente, todo arquivo que o servidor recebe
do cliente é adicionado à árvore base. Embora ainda não mencionado, em todas
as etapas realizadas com sucesso pelo servidor, a árvore base do servidor é
modificada conforme a etapa realizada, ou seja, para cada arquivo ou pasta
removido no servidor, remove-se o nó equivalente na árvore base do servidor.
Todo arquivo transmitido do servidor (para o cliente) com sucesso é adicionado
(ou atualizado) na árvore base do servidor.
Ao fim de toda a operação, a árvore base do servidor contém todas as
alterações realizadas, que também é igual à árvore base no cliente. Para finalizar,
o servidor envia a mensagem de finalização de sincronia, e as conexões são
encerradas (o controle e o DataStreamer). Antes de atualizar a árvore base no
banco de dados, calcula-se o hash dos arquivos que não possuem o hash
calculado.
59
CAPÍTULO 9
9. EXPERIÊNCIAS E RESULTADOS
Devido à natureza do projeto, três experimentos foram realizados, visto
que não existe uma experiência única que fosse capaz de demonstrar todos os
objetivos sendo avaliados.
Todos os experimentos foram realizados dentro do cenário a seguir
descrito. Três computadores foram utilizados durante as experiências, sendo que
dois deles possuíam o Microsoft Windows 7 Professional instalado. Quando
necessário, utilizava-se a distribuição Linux Ubuntu 16.04, também de 64 bits.
Todos os computadores estavam ligados à rede local através do modem
roteador da TP-Link modelo TD-W8968. A forma como os computadores
estavam ligados ao modem-roteador não possui interferência direta na análise de
duas experiências, porém na terceira, que corresponde à experiência de
velocidade de transmissão, essa característica torna-se relevante.
9.1. RECONHECIMENTO DE AMIZADE
9.1.1. Objetivo
Esta experiência consiste em averiguar o funcionamento do sistema de
identificação de computadores e comprovar o funcionamento da formação de
amizade.
9.1.2. Equipamentos
Todos três computadores foram utilizados.
9.1.3. Preparações
Utilizando as operações do próprio projeto, formou-se uma “amizade”
entre dois dos computadores.
Finaliza qualquer instância do projeto que possa estar em execução.
60
9.1.4. Procedimentos
Iniciou-se o projeto em um dos computadores (que será chamado de A)
que possui amizade, e, em seguida, iniciou-se o projeto nos outros dois
computadores, com um intervalo mínimo de 2 segundos (para melhor
identificação posterior) entre eles.
Utilizou-se o comando interno para listar as amizades do computador A.
Finalizou-se o projeto no computador que é amigo de A e utilizou-se o
comando de listagem de amizades novamente em A.
Finalizou-se o projeto no outro computador e, por fim, finalizou-se o
projeto em A.
9.1.5. Resultado
linha tempo mensagem
1 0.078 warn DIG-NOTEBOOK
2 0.334 info tlSock: Init()
3 0.339 info tlSock: Create UDP socket
4 0.359 info tlSock: 0.0.0.0@4970
5 0.363 info tlSock: Init as receiver
6 0.367 info CC: Received Packet
7 0.370 warn CC: Received my own message 8 7.388 info CC: Received Packet
9 7.393 info CC: Received message from 192.168.1.105 code:1 10 7.399 info CC: Received BroadcastHello
11 10.993 info CC: Received Packet 12 10.999 info CC: Received message from 192.168.1.107 code:1
13 11.005 info CC: Received BroadcastHello
14 19.480 info Listing friends:
15 19.486 info DIG-DESKTOP | 192.168.1.105 - 1485978197 16 24.201 info CC: Received Packet
17 24.201 info CC: Received message from 192.168.1.105 code:6
18 24.201 info CC: Received BroadcastConnectionDrop
19 27.764 info Listing friends: 20 27.769 info DIG-DESKTOP | 0.0.0.0 – 0
21 31.266 info CC: Received Packet
22 31.266 info CC: Received message from 192.168.1.107 code:6
23 31.267 info CC: Received BroadcastConnectionDrop
24 33.586 info Kill all
61
25 33.594 info CC: Received Packet 26 33.599 warn CC: Received my own message
27 33.595 info CN: Stopped
28 33.609 info CIc: Stopped
29 33.614 info tlSock: Close socket
30 33.620 info CC: Stopped
31 33.624 info Closing DB Tabela 4 – Log da experiência de reconhecimento de amizade
A Tabela 4 possui o Log produzido pelo computador A durante a
realização da experiência.
9.1.6. Análise dos Resultados
As linhas de 1 a 7 do Log (Tabela 4) correspondem à inicialização do
projeto no computador A. Em particular as linhas 6 e 7 correspondem ao
BroadcastHello que o próprio computador A envia, mais detalhes sobre essa
mensagem foram abordados no capítulo 5.
As linhas 8, 9 e 10 informam que o módulo do núcleo de conectividade
recebeu uma mensagem do tipo BroadcastHello, indicando que o projeto foi
iniciado em outro computador.
As linhas 11, 12 e 13 são similares as três acima, porém correspondem a
outro computador.
As linhas 14 e 15 são os resultados do comando de listagem. Observando
que o amigo foi identificado e o IP dele corresponde a um dos computadores que
acabara de enviar a mensagem de BroadcastHello.
As linhas 16, 17 e 18 correspondem ao recebimento da mensagem de
BroadcastConnectionDrop de um dos computadores.
As linhas 19 e 20 são os resultados do comando de listagem. Observando
que o IP do amigo, que havia sido identificado, foi modificado para o valor nulo.
As linhas 21, 22 e 23 correspondem ao recebimento da mensagem de
BroadcastConnectionDrop de um dos computadores.
As linhas de 24 a 31 correspondem à finalização do projeto no
computador A. Observando que as linhas 25 e 26 correspondem à mensagem de
BroadcastConnectionDrop que o próprio computador A enviou.
62
9.1.7. Conclusão
Pode-se observar que o computador A foi capaz de identificar o “amigo”
com sucesso, tanto quando ele “entrou” (iniciou-se o projeto nele) quanto quando
ele “saiu” (finalizou-se o projeto nele), sem confundir-se, uma vez que o
computador que não era amigo “entrou” depois e também saiu depois.
9.2. SINCRONIA DE PASTAS E ARQUIVOS
9.2.1. Objetivo
Este experimento consiste em averiguar a capacidade do sistema de
realizar sincronia de pastas e arquivos, considerando a maioria dos cenários
possíveis, ou seja, a capacidade de detectar quais pastas ou arquivos devem ser
criados, removidos ou editados.
9.2.2. Equipamentos
Apenas dois computadores foram utilizados.
9.2.3. Preparações
Criou-se uma pasta em cada computador que foi a pasta a ser
sincronizada.
Em um dos computadores (Computador A) criou-se três pastas (a, b & c)
e em cada pasta há duas subpastas com nome de um dos planetas do sistema
solar. Três arquivos compactados em 7zip foram copiados, um para a pasta raiz,
um para uma das pastas e o outro para uma das subpastas.
No outro computador (Computador B) criou-se três pastas (c, d & e) e
em cada pasta há duas subpastas com nome de um dos deuses da mitologia
grega. Também foram copiados três arquivos compactados em 7zip,
similarmente à posição em pastas em que os arquivos foram copiados no
Computador A.
Iniciou-se o projeto e formou-se amizade entre os dois computadores que
participarão da experiência.
9.2.4. Procedimentos
Antes de criar o canal de sincronia, obteve-se o conteúdo da pasta a ser
sincronizada em cada computador, utilizando o próprio projeto.
63
Com o projeto em execução em ambos os computadores, criou-se o canal
de sincronia informando a pasta correta a ser sincronizada. Após concluir a
configuração, o projeto realizou a primeira sincronia.
Após concluir a primeira sincronia, encerrou-se o projeto em execução e
obteve-se o conteúdo da pasta a ser sincronizada em cada computador.
Dois arquivos (file_b0.7z & c/Saturno/file_a2.7z) foram
removidos do Computador A. Enquanto que no Computador B um dois
arquivos (file_a0.7z & c/Saturno/file_a2.7z) foram modificados e
duas pastas (a/Mercurio & e/Hefesto) foram removidas.
Obteve-se o conteúdo da pasta a ser sincronizada em cada computador
pela terceira vez.
Iniciou-se o projeto e aguardou-se até que o processo automático de
sincronia de pastas e arquivos fosse executado e concluído.
Concluído a segunda sincronia, obteve-se o conteúdo da pasta a ser
sincronizada pela última vez.
9.2.5. Resultados
O projeto possui uma ferramenta interna que monta uma DirTree da
pasta desejada (a pasta a ser sincronizada) e exibe (na tela) toda a árvore de
pastas e arquivos contidos na DirTree de forma similar ao comando TREE do
Console do Windows, porém contendo também o MD5 dos arquivos.
Antes e depois de realizar cada uma das sincronias, a ferramenta
supracitada foi utilizada para extrair o conteúdo das pastas e ser possível
verificar as diferenças.
A Tabela 5 possui o resultado da ferramenta utilizada antes de realizar a
primeira sincronia, enquanto que a Tabela 6 possui o resultado da mesma
ferramenta após realizar a primeira sincronia. A coluna da esquerda possui o
conteúdo da pasta a ser sincronizada do Computador A, e a coluna da direita é
do Computador B.
A Tabela 7 possui o resultado da ferramenta utilizada na pasta a ser
sincronizada após realizar as modificações nas pastas e arquivos e antes da
segunda sincronia, conforme descritos no procedimento. Para melhor
64
visualização, as linhas correspondentes aos arquivos e pastas removidas foram
deixadas em “branco” na coluna do computador onde houve modificação, assim
sendo, caso as duas colunas em uma mesma linha não sejam iguais, é por que
elas foram modificadas.
A Tabela 8 contém o resultado da ferramenta na pasta a ser sincronizada
após realizar a segunda sincronia.
Computador A Computador B | file_a0.7z g/DNRL$Xui=QWMK*gC^D | file_b0.7z FqNTHvk5GRtI#Y.1xHs8
| |
+-a +-c
| +-Mercurio | | file_b1.7z M{VnHN}zqlQaex7wP(.]
| \-Venus | |
+-b | +-Hades
| | file_a1.7z pdsIi)RS**bnAnef2AM5 | \-Poseidon
| | +-d
| +-Marte | +-Cronos
| \-Terra | \-Zeus
\-c | | file_b2.7z 6thDLvqj:I)qhY).jX.+
+-Jupter |
\-Saturno \-e
| file_a2.7z k&-c4lspb6{seJS<%8ar +-Hefesto
\-Hera
Tabela 5 – Pasta de sincronia antes da primeira sincronia
Computador A Computador B | file_a0.7z g/DNRL$Xui=QWMK*gC^D | file_a0.7z g/DNRL$Xui=QWMK*gC^D
| file_b0.7z FqNTHvk5GRtI#Y.1xHs8 | file_b0.7z FqNTHvk5GRtI#Y.1xHs8
| |
+-a +-a
| +-Mercurio | +-Mercurio
| \-Venus | \-Venus
+-b +-b
| | file_a1.7z pdsIi)RS**bnAnef2AM5 | | file_a1.7z pdsIi)RS**bnAnef2AM5
| | | |
| +-Marte | +-Marte
| \-Terra | \-Terra
+-c +-c
| | file_b1.7z M{VnHN}zqlQaex7wP(.] | | file_b1.7z M{VnHN}zqlQaex7wP(.]
| | | |
| +-Hades | +-Hades
| +-Jupter | +-Jupter
| +-Poseidon | +-Poseidon
| \-Saturno | \-Saturno
| | file_a2.7z k&-c4lspb6{seJS<%8ar | | file_a2.7z k&-c4lspb6{seJS<%8ar
| |
+-d +-d
| +-Cronos | +-Cronos
| \-Zeus | \-Zeus
| | file_b2.7z 6thDLvqj:I)qhY).jX.+ | | file_b2.7z 6thDLvqj:I)qhY).jX.+
| |
\-e \-e
+-Hefesto +-Hefesto
\-Hera \-Hera
65
Tabela 6 – Pasta de sincronia após a primeira sincronia
9.2.6. Análise dos Resultados
Observando a Tabela 6 e a Tabela 8, que contém o resultado após as
sincronias, é notável que o conteúdo de ambas as pastas ficaram idênticas, tanto
em estrutura quanto em conteúdo, que pode ser observado pelo MD5 dos
arquivos.
Computador A Computador B | file_a0.7z g/DNRL$Xui=QWMK*gC^D | file_a0.7z S7GZH14[*-kj{9)X1F[k
| | file_b0.7z FqNTHvk5GRtI#Y.1xHs8
| |
+-a +-a
| +-Mercurio | |
| \-Venus | \-Venus
+-b +-b
| | file_a1.7z pdsIi)RS**bnAnef2AM5 | | file_a1.7z pdsIi)RS**bnAnef2AM5
| | | |
| +-Marte | +-Marte
| \-Terra | \-Terra
+-c +-c
| | file_b1.7z M{VnHN}zqlQaex7wP(.] | | file_b1.7z M{VnHN}zqlQaex7wP(.]
| | | |
| +-Hades | +-Hades
| +-Jupter | +-Jupter
| +-Poseidon | +-Poseidon
| \-Saturno | \-Saturno
| | | file_a2.7z 3uGRjRPh7L}T%5x}T-ym
| |
+-d +-d
| +-Cronos | +-Cronos
| \-Zeus | \-Zeus
| | file_b2.7z 6thDLvqj:I)qhY).jX.+ | | file_b2.7z 6thDLvqj:I)qhY).jX.+
| |
\-e \-e
+-Hefesto |
\-Hera \-Hera
Tabela 7 – Pasta de sincronia antes da segunda sincronia
Observando a Tabela 5 e a Tabela 6, nota-se que todas as pastas e todos
os arquivos do Computador A foram copiados (e criados) no Computador B,
assim como todas as pastas e todos os arquivos do Computador B foram
copiados no Computador A.
Observado a Tabela 7 nota-se que o arquivo file_b0.7z foi removido
do Computador A, que a pasta a/Mercurio foi removida do Computador B, a
pasta e/Hefesto foi removida do Computador B. Ao comparar a Tabela 7
com a Tabela 6 nota-se as mesmas coisas e nota-se que o arquivo file_a0.7z
66
foi modificado no Computador B. Todas essas modificações estão conforme às
operações realizadas durante o procedimento.
Computador A Computador B | |
| file_a0.7z S7GZH14[*-kj{9)X1F[k | file_a0.7z S7GZH14[*-kj{9)X1F[k
| |
+-a +-a
| \-Venus | \-Venus
+-b +-b
| | file_a1.7z pdsIi)RS**bnAnef2AM5 | | file_a1.7z pdsIi)RS**bnAnef2AM5
| | | |
| +-Marte | +-Marte
| \-Terra | \-Terra
+-c +-c
| | file_b1.7z M{VnHN}zqlQaex7wP(.] | | file_b1.7z M{VnHN}zqlQaex7wP(.]
| | | |
| +-Hades | +-Hades
| +-Jupter | +-Jupter
| +-Poseidon | +-Poseidon
| \-Saturno | \-Saturno
| | file_a2.7z 3uGRjRPh7L}T%5x}T-ym | | file_a2.7z 3uGRjRPh7L}T%5x}T-ym
| |
+-d +-d
| +-Cronos | +-Cronos
| \-Zeus | \-Zeus
| | file_b2.7z 6thDLvqj:I)qhY).jX.+ | | file_b2.7z 6thDLvqj:I)qhY).jX.+
| |
\-e \-e
\-Hera \-Hera
Tabela 8 – Pasta de sincronia após a segunda sincronia
Comparando-se a Tabela 8 com a Tabela 7 (ou até mesmo a Tabela 6)
nota-se que o arquivo file_b0.7z foi removido de ambos os computadores, as
pastas a/Mercurio e e/Hefesto foram removidas de ambos os computadores,
o arquivo c/Saturno/file_a2.7z foi removido do Computador A mas foi
modificado no Computador B, o resultado da sincronia foi criar e copiar o
arquivo do Computador B para o Computador A, e o arquivo file_a0.7z foi
atualizado no Computador A com a modificação realizada no Computador B.
9.2.7. Conclusão
Nota-se que o projeto foi capaz de realizar a sincronia da pasta nos dois
momentos, ou seja, o conteúdo das pastas e arquivos, assim como sua estrutura,
ficaram idênticas em ambos os computadores, e o processo de sincronia foi capaz
de detectar que:
• Arquivos e pastas foram criados (primeira sincronia)
• União de pastas já existentes (pasta c)
67
• Arquivos e pastas foram removidos (segunda sincronia)
• Arquivos foram editados (file_a0.7z)
• Preferência em atualizar arquivo sobre remover arquivo (file_a2.7z)
9.3. TAXAS DE TRANSFERÊNCIA
9.3.1. Objetivo
Este experimento visa obter a taxa média máxima e a taxa média de
transferência de arquivos entre dois computadores em quatro combinações de
conexão possíveis (apenas ethernet, de ethernet para WiFi, de WiFi para
ethernet e apenas WiFi) e em quatro combinações de sistema operacional
possíveis (apenas Windows, de Windows para Linux, de Linux para Windows e
apenas Linux) usando o projeto. Obter a taxa média máxima e taxa média de
transferência de arquivos entre dois computadores nas quatro combinações de
conexão supracitadas, utilizando a ferramenta nativa do Windows.
9.3.2. Equipamentos
Dois computadores foram utilizados. Ambos com o Windows instalado e
ambos possuem tanto placa de rede cabeada quanto placa de rede WiFi com
suporte a WiFi IEEE 802.11n.
9.3.3. Preparações
A rede WiFi foi configurada para operar apenas em IEEE 802.11n.
Dez arquivos, de 100MiB e formato 7Zip, foram criados e utilizados na
experiência.
Utilizando o projeto, formou-se amizade entre os computadores e criou-se
um canal de transferência com a opção de aceitação automática ativada (para
permitir o uso de scripts para automatizar o processo).
9.3.4. Procedimentos
Para cada combinação de conexão e cada combinação de sistema
operacional, cada um dos dez arquivos foi enviado seis vezes. Anotava-se a
velocidade média obtida na transferência, que é calculada pelo projeto de acordo
com o tamanho do arquivo enviado e o tempo gasto, e, das seis amostras de
velocidade média, uma das amostras era descartada, seja por falha ou por
apresentar taxa muito discrepante em relação às outras.
68
Ao final, para cada combinação de conexão e de sistema operacional,
cinquenta amostras de taxa média de transferência foram obtidas.
Para a transferência usando a ferramenta nativa do Windows, anota-se o
tempo do início e o tempo do término. Com base nesses valores e no tamanho
dos arquivos transmitidos, calcula-se a taxa média da transferência. Também
foram obtidas cinquenta amostras de taxa média de transferência
9.3.5. Resultados
Ethernet encontra-se abreviado como eth nos próximos gráficos e tabelas.
A tabela completa com todas as taxas média de transferência (em MiB/s)
obtidas usando o projeto, apresentadas em ordem decrescente de valor,
encontra-se no Apêndice A.
A tabela completa com todas as taxas média de transferência (em MiB/s)
obtidas usando a ferramenta nativa do Windows, apresentada em ordem
decrescente de valor, encontra-se no Apêndice B.
9.3.6. Análise dos Resultados
A Tabela 9 apresenta a média das taxas média das cinquenta
transferências (em MiB/s) em cada combinação de conexão e sistema
operacional, efetuadas usando o projeto. A Tabela 10 contém o desvio padrão
das medidas (em MiB/s) e a Figura 19 contém o gráfico comparativo com os
valores das duas tabelas.
de Windows
para Windows
de Windows
para Linux
de Linux
para Windows
de Linux
para Linux
eth � eth 11.15 11.09 11.25 11.18 eth � wifi 10.50 10.46 10.26 11.06 wifi � eth 9.01 8.73 9.25 9.89 wifi � wifi 4.48 3.62 4.48 4.67
Tabela 9 – Taxa média das transferências (MiB/s)
de Windows
para Windows
de Windows
para Linux
de Linux
para Windows
de Linux
para Linux
eth ���� eth 0.012 0.007 0.006 0.007 eth ���� wifi 0.292 0.177 0.611 0.039 wifi ���� eth 0.208 0.226 0.235 0.062 wifi ���� wifi 0.099 0.102 0.181 0.053
Tabela 10 – Desvio padrão da média das transferências (MiB/s)
69
Figura 19 – Gráfico da média das taxas de transferência obtidas com o projeto (em
MiB/s)
A Tabela 11 apresenta a média das taxas média das cinquenta
transferências, o desvio padrão das médias e o máximo das taxas médias (tudo
em MiB/s) em cada combinação de conexão e sistema operacional, efetuadas
usando a ferramenta nativa do Windows. E a Figura 20 contém o gráfico com as
médias das taxas médias.
Figura 20 – Gráfico da média das taxas de transferência obtidas com a ferramenta
nativa do Windows (em MiB/s)
0
2
4
6
8
10
12
eth para eth eth para wifi wifi para eth wifi para wifi
windows para windows windows para linux linux para windows linux para linux
0
2
4
6
8
10
12
eth para eth eth para wifi wifi para eth wifi para wifi
windows para windows
70
A Tabela 12 contém a máxima taxa de transferência média obtida das
cinquenta transferências, que também pode ser visto no gráfico da Figura 21.
média desvio padrão máximo
eth ���� eth 9.82 0.270 10.26 eth ���� wifi 8.67 1.244 10.19 wifi ���� eth 5.14 1.194 8.12 wifi ���� wifi 2.57 0.355 3.44
Tabela 11 – Taxas das transferências com a ferramenta nativa do Windows (em
MiB/s)
de Windows
para Windows
de Windows
para Linux
de Linux
para Windows
de Linux
para Linux
eth ���� eth 11.19 11.11 11.27 11.21 eth ���� wifi 10.92 10.83 11.11 11.14 wifi ���� eth 9.44 9.12 9.97 10.07 wifi ���� wifi 4.69 3.87 4.84 4.79
Tabela 12 – Taxa máxima das transferências usando o projeto (em MiB/s)
Figura 21 – Gráfico do máximo das taxas de transferência obtidas com o projeto
(em MiB/s)
É interessante notar que a taxa de transferência ao transmitir a partir do
WiFi tem uma queda significativa, isso provavelmente é devido ao próprio TCP
e seu algoritmo de controle de congestionamento e à colisão de pacotes que
ocorre no WiFi. A notar que a taxa de transferência caiu para menos da metade
na configuração de WiFi para WiFi, em relação da configuração WiFi para
0
2
4
6
8
10
12
eth para eth eth para wifi wifi para eth wifi para wifi
windows para windows windows para linux linux para windows linux para linux
71
ethernet, o que é causado pelo aumento da colisão de pacotes no WiFi, visto que
ambos os computadores estão utilizando o mesmo.
Figura 22 – Gráfico do máximo das taxas de transferência obtidas com a ferramenta
nativa do Windows (em MiB/s)
9.3.7. Conclusões
O projeto apresentou taxas excepcionais nas transferências em rede
ethernet de 100Mbps, que possui taxa máxima teórica de 11.9MiB/s, mas
apresentou taxas não tão altas para transferências em rede WiFi apenas,
entretanto essas baixas taxas não são devido ao projeto em si, mas em adotar
TCP para transferências e usá-lo no WiFi.
0
2
4
6
8
10
12
eth para eth eth para wifi wifi para eth wifi para wifi
windows para windows
72
CAPÍTULO 10
10. CONCLUSÃO
Observando o motivo pelo qual este projeto foi movido, analisando os
resultados obtidos em cada uma das experiências, e comparando com os
objetivos desejados e propostos para este projeto, é de extrema satisfação
concluir e apresentar este projeto que atende às expectativas impostas a ele.
Este projeto não necessita de nenhum nó central, pois assim ele foi
planejado e concebido, conforme foi apresentado, principalmente, no capítulo 6.
Assim como também não necessita de acesso à Internet, uma vez que não é
necessário um nó central e o projeto é focado em transferências em rede interna.
O projeto utiliza da premissa de que cada computador possui uma identificação
única dentro de uma rede local para, assim, identificar unicamente cada
computador e, então, utilizar essa identificação, juntamente com as palavras-
chaves geradas no momento em que se forma um vínculo/relacionamento entre
dois computadores, que são usadas no processo de handshake para autenticar o
relacionamento.
Este projeto é capaz de transferir arquivos entre computadores com taxa
de transferência média aceitável e desejável, chegando bem próximo do valor
máximo teórico que a rede suporta na maioria dos casos, conforme foi observado
através da experiência de taxa de transferência, e maior que a taxa de
transferência média obtida usando a ferramenta nativa do Windows para cópia
de arquivos em rede.
Embora as taxas em transferências utilizando apenas o WiFi tenham sido
baixas, esses valores não tem impacto devido apenas ao projeto, mas ao uso do
TCP para transmissão dos arquivos na rede pelo WiFi.
A sincronia de pastas e arquivos é funcional e segue as restrições de
implementação que foram definidas a ela, dentre elas, a tomada de decisão de
não fazer nada quando dois arquivos com mesmo nome são criados ou editados e
73
apresentam conteúdo diferente entre eles, entretanto, nesse cenário, o projeto
envia uma notificação para o usuário informando que o conteúdo dos arquivos
são diferentes.
Um detalhe importante a acrescentar é na escolha de arquivos
compactados em 7Zip nas experiências. Estes arquivos possuem código de
verificação de erro internamente, e isso foi utilizado para verificar se houve
algum erro em alguma transferência, uma vez que o próprio programa que cria
esses arquivos também é capaz de verificar a integridade do mesmo, durante a
fase de criação do algoritmo de transferência. Além disso, por ser um arquivo
compactado, é mais fácil de criar ele com um tamanho desejado, bastando
apenas acrescentar ou remover arquivos de dentro dele, conforme foi feito para
obter os arquivos de 100MB da experiência de taxa de transferência.
10.1. PROJETOS FUTUROS
Há intenção de acrescentar melhorias a este projeto, não apenas
funcionais ou para otimização como também estéticos para facilitar o uso do
mesmo. Dentre as melhorias há:
• Criptografia nas transferências e sincronias
Para aumentar a segurança do projeto e possibilitar o uso do mesmo com
informações mais sigilosas ou em redes com segurança comprometida ou baixa,
sem que haja prejuízo na taxa de transferência.
• Criptografia nas mensagens de controle
Para aumentar a segurança do projeto não apenas no conteúdo dos
arquivos transferidos, mas aumentar a segurança do próprio projeto para reduzir
chances de ataque.
• Algoritmo otimizado para transferência de pequenos arquivos
Atualmente é enviado apenas um arquivo por vez e, quando se transfere
vários arquivos pequenos, a taxa de transferência sofre uma queda. Otimizar o
projeto para esse caso é algo desejado.
74
• Algoritmo em UDP para transferências
A fim de aumentar a taxa de transferência de arquivos entre
computadores conectados em rede WiFi, que correspondem aos casos mais
comuns hoje em dia.
• Dispositivos intermediadores
Permitir que haja transferência de arquivos entre dois computadores que
não estejam em uma mesma rede local, mas que exista um dispositivo que seja
capaz de agir como um intermediador para realizar a transferência, ou seja, que
este dispositivo possa entrar em contato com cada um dos dois computadores,
permitindo que a comunicação entre eles seja feita por meio deste dispositivo.
75
REFERÊNCIAS BIBLIOGRÁFICAS
[1] C++ Reference. C++ Reference. [Online]. Disponível em: <http://www.cplusplus.com/reference/>. Acesso em: 27 de Maio de 2015
[2] ISO/IEC. (2011, Setembro) ISO/IEC 14882:2011. [Online]. Disponível em: <http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372>. Acesso em: 17 de Julho de 2016
[3] GNU Compiler Collection. GCC, The GNU Compiler Collection. [Online]. Disponível em: <https://gcc.gnu.org/>. Acesso em: 17 de Julho de 2016
[4] Mingw-w64. Mingw-w64 - GCC for Windows. [Online]. Disponível em: <http://mingw-w64.org/>. Acesso em: 9 de Março de 2015
[5] RFC1122. RFC1122 - Requirements for Internet Hosts -- Communication Layers. [Online]. Disponível em: <https://tools.ietf.org/html/rfc1122>. Acesso em: 22 de 04 de 2015
[6] RFC1123. RFC 1123 - Requirements for Internet Hosts -- Application and Support. [Online]. Disponível em: <https://tools.ietf.org/html/rfc1123>. Acesso em: 22 de 04 de 2015
[7] JSON. JSON. [Online]. Disponível em: <http://www.json.org/>. Acesso em: Maio de 2015
[8] Gustavo de Oliveira Silva. DIG Logger. [Online]. Disponível em: <https://bitbucket.org/diguser/dig-logger>. Acesso em: 27 de Junho de 2016
[9] Jonathan Wallace. libjson. [Online]. Disponível em: <https://sourceforge.net/projects/libjson/>. Acesso em: 27 de Junho de 2016
[10] ARMmbed. SSL Library mbed TLS / PolarSSL. [Online]. Disponível em: <https://tls.mbed.org/>. Acesso em: 27 de Junho de 2016
[11] SQLite. SQLite. [Online]. Disponível em: <https://www.sqlite.org/index.html>. Acesso em: 27 de Junho de 2016
[12] Stanislav Artemkin. (2013) Z85. [Online]. Disponível em: <https://travis-ci.org/artemkin/z85>. Acesso em: 3 de Junho de 2016
[13] Network World. Are MAC addresses really unique? [Online]. Disponível em: <http://www.networkworld.com/article/2340364/lan-wan/are-mac-addresses-really-unique-.html>. Acesso em: 27 de Junho de 2016
[14] The Linux Information Project. TCP Definition. [Online]. Disponível em: <http://www.linfo.org/tcp.html>. Acesso em: 27 de Junho de 2016
[15] Quora. Why are MAC addresses unique when they are supposed to be used within a LAN? Are MAC addresses transmitted across the Internet also? [Online]. Disponível em: <https://www.quora.com/Why-are-MAC-
76
addresses-unique-when-they-are-supposed-to-be-used-within-a-LAN-Are-MAC-addresses-transmitted-across-the-Internet-also>. Acesso em: 27 de Junho de 2016
[16] zlib. zlib. [Online]. Disponível em: <http://www.zlib.net/>. Acesso em: 27 de Junho de 2016
[17] Linux Documentation. Linux Documentation. [Online]. Disponível em: <http://linux.die.net/>. Acesso em: 22 de Março de 2015
77
APÊNDICE A
A tabela abaixo contém as taxas médias de transferência obtidas na
experiência de taxas de transferência usando o projeto.
Todos os valores estão em MiB/s.
eth para eth eth para wifi De: windows windows linux linux windows windows linux linux
Para: windows linux windows linux windows linux windows linux
1 11.20 11.12 11.27 11.21 10.92 10.83 11.12 11.14
2 11.18 11.11 11.27 11.21 10.89 10.81 11.10 11.13
3 11.17 11.11 11.27 11.20 10.88 10.78 11.08 11.12
4 11.17 11.11 11.27 11.20 10.88 10.77 11.05 11.12
5 11.17 11.11 11.27 11.19 10.88 10.77 11.04 11.11
6 11.17 11.10 11.26 11.19 10.88 10.71 11.03 11.11
7 11.17 11.10 11.26 11.19 10.86 10.64 11.03 11.11
8 11.17 11.10 11.26 11.19 10.84 10.62 11.02 11.10
9 11.17 11.10 11.26 11.19 10.84 10.62 10.95 11.10
10 11.16 11.10 11.26 11.19 10.82 10.60 10.93 11.10
11 11.16 11.10 11.26 11.19 10.82 10.59 10.93 11.10
12 11.16 11.10 11.26 11.19 10.81 10.59 10.89 11.10
13 11.16 11.10 11.26 11.19 10.75 10.59 10.85 11.09
14 11.16 11.10 11.26 11.19 10.74 10.59 10.84 11.09
15 11.16 11.10 11.26 11.19 10.71 10.58 10.77 11.09
16 11.16 11.10 11.26 11.19 10.70 10.57 10.77 11.09
17 11.16 11.10 11.26 11.18 10.68 10.56 10.74 11.09
18 11.16 11.10 11.26 11.18 10.67 10.56 10.71 11.09
19 11.16 11.10 11.26 11.18 10.64 10.55 10.64 11.09
20 11.16 11.10 11.26 11.18 10.64 10.54 10.62 11.08
21 11.16 11.10 11.26 11.18 10.62 10.52 10.60 11.08
22 11.16 11.09 11.26 11.18 10.61 10.48 10.57 11.08
23 11.16 11.09 11.26 11.18 10.60 10.48 10.55 11.07
24 11.15 11.09 11.25 11.18 10.59 10.47 10.50 11.07
25 11.15 11.09 11.25 11.18 10.59 10.46 10.42 11.06
26 11.15 11.09 11.25 11.18 10.57 10.45 10.40 11.06
27 11.15 11.09 11.25 11.18 10.52 10.44 10.17 11.06
28 11.15 11.09 11.25 11.18 10.51 10.43 10.09 11.06
29 11.15 11.09 11.25 11.18 10.45 10.42 10.01 11.06
30 11.15 11.09 11.25 11.18 10.41 10.42 10.01 11.06
31 11.15 11.09 11.25 11.18 10.38 10.42 9.89 11.06
32 11.15 11.09 11.25 11.18 10.34 10.42 9.78 11.06
33 11.15 11.09 11.25 11.18 10.33 10.40 9.76 11.05
78
34 11.14 11.09 11.25 11.18 10.32 10.37 9.74 11.05
35 11.14 11.09 11.25 11.18 10.30 10.36 9.70 11.04
36 11.14 11.09 11.25 11.18 10.29 10.35 9.67 11.04
37 11.14 11.09 11.25 11.18 10.28 10.35 9.66 11.03
38 11.14 11.09 11.25 11.18 10.28 10.29 9.61 11.02
39 11.14 11.09 11.25 11.18 10.28 10.27 9.58 11.02
40 11.14 11.09 11.25 11.18 10.24 10.26 9.58 11.02
41 11.14 11.09 11.25 11.18 10.22 10.26 9.56 11.02
42 11.14 11.09 11.25 11.18 10.19 10.25 9.54 11.02
43 11.14 11.09 11.25 11.18 10.18 10.24 9.53 11.02
44 11.14 11.09 11.25 11.18 10.15 10.24 9.52 11.01
45 11.14 11.09 11.25 11.18 10.14 10.23 9.51 11.01
46 11.14 11.09 11.25 11.18 10.02 10.23 9.50 11.00
47 11.14 11.08 11.25 11.18 10.00 10.22 9.48 11.00
48 11.14 11.08 11.25 11.18 9.99 10.21 9.47 11.00
49 11.14 11.08 11.25 11.18 9.98 10.20 9.45 11.00
50 11.14 11.08 11.25 11.18 9.93 10.20 9.44 10.98
wifi para eth wifi para wifi De: windows windows linux linux windows windows linux linux
Para: windows linux windows linux windows linux windows linux
1 9.45 9.13 9.98 10.08 4.69 3.87 4.85 4.79
2 9.37 9.11 9.88 10.06 4.64 3.85 4.79 4.76
3 9.30 9.09 9.77 10.03 4.63 3.79 4.78 4.75
4 9.28 9.04 9.48 10.00 4.61 3.78 4.77 4.75
5 9.28 9.04 9.47 10.00 4.60 3.77 4.75 4.74
6 9.27 9.03 9.45 9.98 4.59 3.76 4.74 4.74
7 9.27 9.02 9.45 9.95 4.59 3.76 4.72 4.74
8 9.26 9.01 9.43 9.95 4.59 3.75 4.70 4.73
9 9.24 9.00 9.42 9.95 4.58 3.73 4.70 4.73
10 9.24 8.99 9.41 9.94 4.58 3.71 4.70 4.72
11 9.23 8.94 9.40 9.94 4.58 3.71 4.67 4.72
12 9.23 8.94 9.39 9.94 4.57 3.70 4.65 4.72
13 9.23 8.93 9.38 9.94 4.56 3.69 4.62 4.71
14 9.21 8.93 9.38 9.93 4.56 3.68 4.60 4.71
15 9.14 8.91 9.37 9.93 4.54 3.68 4.59 4.71
16 9.12 8.91 9.35 9.93 4.53 3.67 4.59 4.70
17 9.11 8.89 9.34 9.92 4.53 3.66 4.55 4.70
18 9.11 8.87 9.33 9.92 4.53 3.66 4.54 4.70
19 9.09 8.86 9.32 9.91 4.53 3.65 4.54 4.69
20 9.08 8.85 9.31 9.91 4.53 3.64 4.53 4.69
21 9.07 8.83 9.31 9.90 4.52 3.64 4.53 4.69
79
22 9.04 8.77 9.30 9.89 4.52 3.63 4.49 4.68
23 9.02 8.74 9.29 9.89 4.51 3.62 4.48 4.68
24 9.01 8.73 9.28 9.89 4.50 3.62 4.46 4.68
25 9.01 8.71 9.28 9.88 4.50 3.61 4.46 4.67
26 9.00 8.70 9.26 9.88 4.50 3.61 4.46 4.67
27 9.00 8.70 9.25 9.88 4.48 3.59 4.45 4.67
28 9.00 8.69 9.24 9.88 4.47 3.59 4.43 4.66
29 8.97 8.68 9.24 9.88 4.47 3.58 4.42 4.66
30 8.94 8.65 9.24 9.87 4.47 3.58 4.42 4.66
31 8.91 8.64 9.23 9.87 4.47 3.57 4.42 4.64
32 8.91 8.64 9.23 9.87 4.46 3.57 4.40 4.64
33 8.90 8.64 9.21 9.87 4.45 3.57 4.37 4.63
34 8.89 8.63 9.18 9.86 4.43 3.56 4.37 4.63
35 8.89 8.61 9.16 9.86 4.42 3.56 4.35 4.63
36 8.88 8.59 9.12 9.86 4.41 3.55 4.35 4.63
37 8.85 8.58 9.10 9.85 4.41 3.55 4.35 4.63
38 8.84 8.58 9.07 9.85 4.39 3.53 4.35 4.63
39 8.83 8.52 9.06 9.85 4.38 3.53 4.35 4.62
40 8.81 8.52 9.06 9.85 4.38 3.53 4.34 4.62
41 8.79 8.51 9.03 9.84 4.37 3.53 4.33 4.62
42 8.79 8.49 9.01 9.84 4.36 3.52 4.31 4.62
43 8.78 8.45 8.99 9.84 4.36 3.51 4.31 4.62
44 8.77 8.44 8.99 9.84 4.35 3.51 4.30 4.61
45 8.75 8.41 8.97 9.83 4.34 3.49 4.28 4.61
46 8.73 8.41 8.96 9.83 4.33 3.48 4.24 4.61
47 8.70 8.40 8.92 9.82 4.33 3.48 4.24 4.60
48 8.70 8.39 8.87 9.82 4.32 3.48 4.17 4.60
49 8.65 8.38 8.85 9.82 4.32 3.48 4.16 4.58
50 8.64 8.34 8.85 9.82 4.31 3.47 4.14 4.57
80
APÊNDICE B
A tabela abaixo contém as taxas médias de transferência obtidas na
experiência de taxas de transferência usando a ferramenta nativa do Windows.
Todos os valores estão em MiB/s.
windows para windows De: eth eth wifi wifi eth eth wifi wifi
Para: eth wifi eth wifi eth wifi eth wifi
1 10.26 10.19 8.12 3.44 26 9.79 9.28 5.36 2.55
2 10.24 10.12 7.05 3.38 27 9.77 9.26 5.34 2.54
3 10.23 10.07 6.97 3.12 28 9.76 9.14 4.89 2.54
4 10.22 10.02 6.88 3.11 29 9.71 9.12 4.81 2.52
5 10.21 10.00 6.69 3.10 30 9.67 8.94 4.60 2.49
6 10.21 9.92 6.58 3.08 31 9.67 8.39 4.53 2.45
7 10.17 9.80 6.57 3.07 32 9.67 8.39 4.46 2.42
8 10.16 9.78 6.53 2.93 33 9.67 8.30 4.38 2.39
9 10.15 9.75 6.23 2.91 34 9.66 8.28 4.38 2.33
10 10.10 9.75 6.14 2.87 35 9.65 7.97 4.28 2.33
11 10.07 9.75 6.02 2.85 36 9.64 7.88 4.25 2.32
12 10.04 9.73 5.93 2.80 37 9.61 7.86 4.16 2.30
13 10.04 9.59 5.89 2.79 38 9.58 7.60 4.03 2.28
14 10.03 9.54 5.89 2.79 39 9.58 7.37 4.03 2.24
15 10.03 9.53 5.86 2.77 40 9.58 7.31 3.95 2.21
16 10.03 9.53 5.80 2.73 41 9.54 6.98 3.93 2.19
17 10.02 9.52 5.79 2.72 42 9.52 6.93 3.87 2.16
18 10.01 9.49 5.75 2.70 43 9.51 6.82 3.83 2.15
19 10.00 9.45 5.73 2.64 44 9.50 6.77 3.68 2.15
20 9.96 9.41 5.71 2.61 45 9.47 6.73 3.68 2.10
21 9.95 9.39 5.70 2.60 46 9.46 6.71 3.51 2.10
22 9.95 9.37 5.64 2.59 47 9.44 6.64 3.42 2.09
23 9.90 9.35 5.55 2.58 48 9.42 6.56 3.31 2.09
24 9.86 9.33 5.46 2.57 49 9.41 6.48 3.28 2.06
25 9.82 9.30 5.44 2.56 50 9.39 5.98 3.10 2.06