1. Como depurar o programa?

-analisar os códigos de retorno de todas as chamadas de sistema.

-usar o comando nc (netcat) para testar separadamente processos clientes e processos servidores.

-usar a aplicação Wireshark (https://www.wireshark.org) para visualizar as mensagens trocadas entre clientes e servidores.

-usar um depurador (ex. gdb ou xxgdb) ou printf() estrategicamente colocados no código para acompanhar a sequência a execução do código de um servidor.

 

2. Qual a dimensão do anel?

A dimensão do anel pode ser fixa, estipulada num #define. 

 

3. É necessário usar fork() ou thread()?

Não precisam usar fork() nem thread(). A multiplexagem de todas as comunicações a que um servidor tem que atender deve ser realizada com a chamada de sistema select().

 

4. Um servidor pode pertencer a mais do que um anel?

Não porque não incluímos forma de distinguir diferentes anéis num servidor. 


5. A leitura com read() de um descritor correspondente a um socket TCP deve ocorrer um byte de cada vez?

Fica ao critério do programador. A leitura de um byte de cada vez torna o programa mais simples porque ao ler um byte pode-se logo identificar se esse byte é o terminador de uma mensagem que no caso do projeto é o \n. Por outro lado, o read() é uma chamada de sistema lenta, ou seja, quantas menos invocações de read() melhor. É mais eficiente capturar mais bytes num só read(). Se fizerem isso terão que analisar os bytes recebido detetando terminadores de mensagens nos bytes que leram.


6. Como é que que uma aplicação se apercebe que uma das sessões TCP terminou?

Quando uma sessão TCP termina, se a aplicação executar, ou estiver bloqueada, no select(), a monitorizar o descritor dessa sessão, o select() termina e assinala esse descritor como estando pronto para leitura. Subsequentemente o read() irá retornar 0, ou -1, assinalando que a sessão terminou.

Se uma sessão TCP tiver terminado e a aplicação executar sobre o descritor dessa sessão um write(), o write() retornará -1 e a variável global errno irá assumir o valor EPIPE assinalando que a sessão associada a esse descritor terminou.

Este comportamento do write() requer que a aplicação assinale ao sistema operativo que o sinal SIGPIPE deve ser ignorado (ver página 13 do guia). Caso contrário, ao se executar um write() sobre um descritor cuja sessão terminou irá resultar em que o sistema operativo irá enviar à aplicação o sinal SIGPIPE (sinal 13) o que irá terminar a aplicação.