Atividade 1 (opcional): Serviço de eco TCP simplificado

Um servidor de eco provê um serviço bastante simples: envia de volta ao cliente tudo o que êle recebe do mesmo. No que se segue suporemos que o clente envia ao servidor linha por linha de um arquivo texto qualquer: o arquivo é lido a partir da entrada padrão (stdin) e as linhas ecoadas pelo servidor são enviadas pelo cliente para a saída padrão (stdout); isto é conveniente pois redirecionando a entrada padrão distintos arquivos podem ser lidos e ecoados. Por outro lado, se estivermos iteressados em fazer medidas do tempo de transito de pacotes pela rede, a saída padrão pode ser redirecionada para /dev/null, eliminando assim o tempo de saída no vídeo; da mesma forma, o tempo de leitura do arquivo a partir do disco pode ser eliminado "cacheando-o" na memória principal, por exemplo, via   cat nome-arquivo (ou executando o programa mais de uma vez). Um esqueleto do laço principal do programa cliente, chame-o   client_echo.c aparece a seguir:
 inicie a contagem de tempo (veja man 2 times e man 3 sysconf)(*)
 1. leia uma linha da entrada padrão enquanto não for EOF (use fgets(..., stdin))(*)
 2. envie a linha lida ao servidor  (via send() ou write())
 3. leia do socket a linha ecoada pelo servidor (via recv() ou read() )
 4. escreva a linha recebida na saída padrão (use fputs(..., stdout))
    volte ao passo 1
 5. finalize a contagem de tempo e exiba as seguintes estatísticas na saída de
    erro (stderr):
	 número de linhas enviadas, tamanho em caracteres da maior linha, 
	 número total de caracteres enviados, número de linhas recebidas,
	 número total de caracteres recebidos,
	 tempo total em segundos(com precisão de 0.1 s)
O que V. deve fazer:
  1. Modifique o programa client0.c de forma a torná-lo um cliente do serviço de eco, (client_echo.c) conforme especificado acima.
  2. Modifique o programa server0.c (chame-o   server_echo.c) de forma a ler do socket conectado e enviar de volta o que foi lido. V. deve contar o número de leituras e o total de caracteres lidos, mostrando o total desses valores na saída de erro (stderr) quando o socket for fechado para escrita do lado do cliente. Lembre-se que um programa deteta o fechamento do socket pelo outro lado quando a leitura pelo socket (via recv() ou read() ) retorna 0 bytes. Devido à característica de interação do tipo "pedido-resposta" do cliente, as leituras/escritas no servidor corresponderão às linhas enviadas pelo cliente, conforme visto em aula. Normalmente isto não é verdade.
    Veja a seguir um esqueleto do programa servidor   server_echo.c:
     int sockfd, conn_fd;  /* listen on sock_fd, new connection on new_fd */
     struct sockaddr_in my_addr;    /* dados do "socket local" do servidor*/
     struct sockaddr_in their_addr; /* para dados do soclet remoto" do cliente */
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        inicialize a struct my_addr
        bind()
        listen()
        conn_fd = accept()
        while ( (nbytes =read(conn_fd, recvline, MAXLINE)) > 0) {
    	   write(conn_fd, recvline,nbytes) 
        }
        close(conn_fd)
    
  3. Meça o tempo para ecoar o arquivo /etc/termcap executando o comando (**):
        client_echo nome_maquina_servidora < /etc/termcap > /dev/null
    
    Compare o número total de linhas e caracteres recebidos com a saída do utilitário   wc.

  4. Transforme o programa   server_echo.c num servidor concorrente (veja o exemplo do tutorial de Beej, server.c ); teste-o a partir de duas instancias do cliente transmitindo simultaneamente dois arquivos para o servidor.


(*) Sempre que tiver dúvidas sobre a sintaxe de uma função em C consulte a man page correspondente!

(**)Todas as medidas de tempo das atividades a serem apresentadas visam obter tempos de transmissão/recepção na rede + tempo de processamento pelo kernel TCP ou UDP; não devem ser influenciadas por tempos de saída no vídeo seja no cliente ou no servidor, tempos de abertura de conexão e por tempos de leitura de arquivos do disco. Esta é a razão pela qual as estatíticas solicitadas devem ser enviadas para a saída de erro (stderr) e não para a saída padrão (stdout) As medidas de tempo devem ser feitas com o cliente e servidor em subredes distintas, por exemplo, o cliente numa das máquinas dos laboratórios e o servidor na xaveco.