Neste trabalho, o objetivo é a criação de um mensageiro: Um aplicativo que possibilita o envio de mensagens, similar ao WhatsApp, Telegram, Signal, Skype, ICQ e MSN Messenger. Este mensageiro será composto de um servidor e de um cliente que rodam em computadores diferentes e se comunicam através de um cabo Ethernet. O mensageiro deverá ser capaz de enviar mensagens de texto e também de trocar arquivos de mídia. O servidor precisa funcionar com apenas um cliente, e um cliente se conecta a apenas um servidor, sendo fora do escopo do trabalho a implementação de um mensageiro que suporta mais de duas pessoas.
Os dois usuários devem ser capazes de fazer envios de mensagem de texto com todos os caracteres disponíveis na codificação UTF-8. Isso inclui por exemplo letras acentuadas e emojis.
As mensagens devem ser enviadas utilizando para-e-espera, onde próxima mensagem só é enviada após a confirmação (ACK) da mensagem anterior.
Os dois usuários devem ser capazes de fazer envios de qualquer tipo de arquivo de mídia, independente do formato e do tamanho do arquivo.
Visto que arquivos de mídia podem ter tamanhos arbitrários, o uso de janelas deslizantes é necessário independente da quantidade de arquivos enviados de uma só vez.
A janela deve ser volta-N, sendo um bônus implementa janela seletiva. O tamanho da janela é de 16.
[<data e hora>]<Usuário> : mensagem
[<data e hora>]<Usuário> : "Arquivo de midia enviado! O arquivo pode ser encontrado em <caminho_para_arquivo>"
i
: Inicia a criação de uma mensagem. Enter para enviar.<esc>
: Sai do modo de inserção de uma mensagem.:q<enter>
: Sai do programa.:send x<enter>
: Envia arquivo x.<control-e>
: Inicia inserção de um arquivo para envio. Enter para enviar.<control-q>
: Sai do programa.O protocolo é inspirado no Kermit e possui os seguintes campos, na ordem que eles são enviados na rede:
Marcador de início | Tipo | Sequência | Tamanho | Dados | CRC-8 |
---|---|---|---|---|---|
8 bits | 6 bits | 4 bits | 6 bits | n bytes | 8 bits |
A memória é endereçada por byte, então alguns campos serão contemplados por partes de alguns bytes, podendo também utilizar vários bytes. Sugere-se a implementação utilizando bit fields do C ou C++. Um buffer de bytes pode ser reinterpretado (feito cast
) como uma struct de bit fields, mas tenha cuidado com o padding que o compilador pode colocar na suas estruturas, além do fato de isso não ser portável em arquiteturas com endianness diferentes (neste trabalho você pode considerar que usaremos apenas processadores little-endian). Os tipos de cada um dos campos serão definidos em aula e seguem.
01111110
(126 em decimal, ou 0x7e
em hexadecimal).0x01
0x10
0x0A
0x00
0x1E
0x1D
0x0F
0x0D
0x9B
(0b10011011
). Algoritmos para cálculo do CRC podem ser encontrados na Internet.
Ao se codificar inteiros em vários bytes, utilize a codificação little-endian, isto é, o byte menos significativo vem primeiro. Note que isto é diferente do padrão da rede. O padrão da rede é utilizar a codificação big-endian (e a função htons
é utilizada para normalizar para big-endian), onde os bytes mais significativos vem primeiro (por exemplo, um IP 127.0.0.1
seria codificado como 0x7f 0x00 0x00 0x01
). Se optou por esta escolha simplesmente por uma questão pragmática: Os processadores com que trabalhamos são em sua maioria little-endian.
Criar diagramas de sequencia
statvfs
(utilizando como caminho, onde se pretende salvar os arquivos que forem recebidos). O espaço livre em bytes é dado por st.f_bsize * st.f_bavail
, onde st
é a estrutura statvfs
.stat
. O tamanho do arquivo em bytes pode ser encontrado em st.st_size
onde st
é a estrutura stat
.