Buscar

Transferência e Sincronia de Arquivos em Rede Local

Prévia do material em texto

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 exclusivoda 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 utilizaAES (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 usode 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çãodo 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 seremrealizadas. 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 oprefixo 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çõespossui 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

Mais conteúdos dessa disciplina