especificacao_trabalho_i

Action disabled: register

Trabalho I: Mensageiro Local

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.

  • Mensagens de texto enviadas devem ser apresentada no formato:
 [<data e hora>]<Usuário> : mensagem
  • Cada mensagem enviada deve ser apresentada separadamente
  • Em mídias enviadas, não é necessário apresentar a mídia, apenas notificar o usuário que uma mídia foi enviada e o local em que pode ser encontrada. Sugestão:
[<data e hora>]<Usuário> : "Arquivo de midia enviado! O arquivo pode ser encontrado em <caminho_para_arquivo>"
  • De forma semelhante ao editor de texto modal vi ou de atalhos emacs, o envio de mensagens e mídias pode ser feito via comandos. Por exemplo:
    • Como vi
      • 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.
    • Como emacs
      • Sempre em modo de criação de uma mensagem. Enter para enviar.
      • <control-e>: Inicia inserção de um arquivo para envio. Enter para enviar.
      • <control-q>: Sai do programa.
  • O seu programa deverá fazer um log. Veja um programa exemplo para ilustrar a criação de um bom log.

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.

  • Marcador de início: A sequência de bits 01111110 (126 em decimal, ou 0x7e em hexadecimal).
  • Tipo: Pode ser um de
    • texto: 0x01
    • mídia: 0x10
    • ack: 0x0A
    • nack: 0x00
    • erro: 0x1E
    • inicio de transmissão: 0x1D
    • fim de transmissão: 0x0F
    • dados: 0x0D
  • Sequência: A sequência local da mensagem, devendo ser incrementada pela própria máquina ao enviar. Esta sequência varia de 0 a 15 de forma circular.
  • Tamanho: Tamanho do campo de dados, não incluindo nenhum outro campo do protocolo, variando de 0 a 63 bytes. Isso significa que o tamanho máximo de uma mensagem completa, com todos os campos, é de 63 (dados) + 3 (cabeçalho) + 1 (verificação) = 67 bytes.
  • Dados: Campo definido de acordo com o tipo da mensagem e de tamanho definido pelo campo anterior.
    • texto: este campo codifica o texto da mensagem em UTF-8.
    • mídia: este campo codifica o início do envio de um arquivo, e deve conter o tamanho do arquivo em bytes utilizando 4 bytes.
    • ack: este campo codifica até qual sequência foi aceita (inclusive) em 1 byte.
    • nack: este campo codifica qual sequência não foi recebida corretamente em 1 byte, e pede retransmissão da mesma.
    • erro: este campo codifica um erro em 1 byte da enumeração:
      • mídia rejeitada devido a espaço insuficiente para arquivo: 207
  • CRC-8: A soma de verificação da mensagem, que deve ser feita em relação ao campo de dados. Caso o tamanho do mesmo seja zero, esse campo ficará zerado. Deve ser utilizado uma verificação cíclica de redundância de 8 bits. Existem alguns polinômios disponíveis, e você pode escolher o que utilizar. O polinômio utilizado no 3G (WCDMA) por exemplo é o x8+x7+x4+x3+x+1 codificado no número 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.

  • O trabalho deve ser escrito em C ou C++.
  • Devem ser utilizados sockets crus.
  • É necessário o uso de timeout.
  • É necessário permissão root para execução do trabalho. Os computadores do DINF não aceitam comandos root por parte dos alunos, logo é necessário ou levar pendrives bootáveis, ou computador próprio para a apresentação do trabalho. Uma distribuição que funciona em memória é o antiX Linux, o que permite utilizar apenas um único pendrive para bootar dois ou mais computadores.

Criar diagramas de sequencia

  • Para verificar se uma sequência vem depois da outra, pense na diferença das sequências: É grande o suficiente pra estarem no meio, ou nas bordas? O algoritmo que você vai acabar criando é aquele de aritmética de números seriais.
  • Para verificar quanto espaço livre uma máquina tem (lembre-se também de ter uma certa tolerância), use a função 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.
  • Para descobrir que o arquivo é regular e o tamanho do arquivo, utilize a função stat. O tamanho do arquivo em bytes pode ser encontrado em st.st_size onde st é a estrutura stat.
  • Note onde há troca de responsabilidade de enviar ACKs e NACKs. Sempre apenas uma das partes (servidor ou cliente) é responsável pelo seu envio, mas pode acontecer delas não saberem que precisam trocar de responsabilidade. Recomenda-se armazenar a última mensagem recebida e a última mensagem enviada caso seja necessário repeti-la.
  • especificacao_trabalho_i.txt
  • Última modificação em: 2022/12/16 12:28
  • por fmkiotheka