Neste laboratrio, ser desenvolvido um servidor Web em duas etapas. No final, voc
ter construdo um servidor Web multithreaded, que ser capaz de processar mltiplas
requisies de servios simultneas em paralelo. Voc dever demonstrar que seu
servidor Web capaz de enviar sua home page ao browser Web.
Implementaremos a verso 1.0 do HTTP, definido na RFC-1945, onde requisies
HTTP separadas so enviadas para cada componente da pgina Web. Este servidor
dever manipular mltiplas requisies simultneas de servios em paralelo. Isso
significa que o servidor Web multithreaded. No thread principal, o servidor escuta
uma porta fixa. Quando recebe uma requisio de conexo TCP, ele ajusta a conexo
TCP atravs de outra porta e atende essa requisio em um thread separado. Para
simplificar esta tarefa de programao, desenvolveremos o cdigo em duas etapas. No
primeiro estgio, voc ir escrever um servidor multithreaded que simplesmente exibe o
contedo da mensagem de requisio HTTP recebida. Assim que esse programa
funcionar adequadamente, voc adicionar o cdigo necessrio para gerar a resposta
apropriada.
Enquanto voc desenvolve o cdigo, pode testar seu servidor a partir de um browser
Web. Mas lembre que o servidor no est atendendo pela porta padro 80; logo,
preciso especificar o nmero da porta junto URL que voc fornecer ao browser Web.
Por exemplo, se o nome da sua mquina host.someschool.edu, seu servidor est
escutando a porta 6789, e voc quer recuperar o arquivo index.html, ento deve
especificar ao browser a seguinte URL:
http://host.someschool.edu:6789/index.html
Se voc omitir :6789, o browser ir assumir a porta 80, que, provavelmente, no ter
nenhum servidor escuta.
Quando o servidor encontra um erro, ele envia uma mensagem de resposta com a fonte
HTML apropriada, de forma que a informao do erro seja exibida na janela do
browser.
}
}
final class HttpRequest implements Runnable
{
A seguir, abrimos um socket e esperamos por uma requisio de conexo TCP. Como
estaremos atendendo a mensagens de requisio indefinidamente, colocamos a operao
de escuta dentro de um lao infinito. Isso significa que precisaremos terminar o servidor
Web digitando ^C pelo teclado.
// Estabelecer o socket de escuta.
?
// Processar a requisio de servio HTTP em um lao infinito.
While (true)
principal realiza o mesmo processo de criao de thread, a menos que o thread anterior
tenha terminado a execuo ou ainda esteja rodando.
Isso completa o cdigo em main(). Para o restante do laboratrio, falta o
desenvolvimento da classe HttpRequest.
Declaramos duas variveis para a classe HttpRequest: CRLF e socket. De acordo com a
especificao HTTP, precisamos terminar cada linha da mensagem de resposta do
servidor com um carriage return (CR) e um line feed (LF), assim definimos a CRLF de
forma conveniente. A varivel socket ser usada para armazenar uma referncia ao
socket de conexo. A estrutura da classe HttpRequest mostrada a seguir:
final class HttpRequest implements Runnable
{
final static String CRLF = \r\n;
Socket socket;
// Construtor
public HttpRequest(Socket socket) throws Exception
{
this.socket = socket;
}
// Implemente o mtodo run() da interface Runnable.
Public void run()
{
}
private void processRequest() throws Exception
{
}
}
devemos definir um mtodo pblico chamado run() que retorna void. A maior parte do
processamento ocorrer dentro do processRequest(), que chamado de dentro do
run().
Agora estamos preparados para capturar mensagens de requisio dos clientes, fazendo
a leitura dos trechos de entrada do socket. O mtodo readLine() da classe
5
BufferedReader
System.out.println();
System.out.println(requestLine);
chegar a zero, ou seja, quando o headerLine tiver comprimento zero. Isso acontecer
quando a linha vazia ao final do cabealho for lida.
Na prxima etapa deste laboratrio, iremos adicionar o cdigo para analisar a
mensagem de requisio do cliente e enviar uma resposta. Mas, antes de fazer isso,
vamos tentar compilar nosso programa e test-lo com um browser. Adicione as linhas a
seguir ao cdigo para fechar as cadeias e conexo de socket.
// Feche as cadeias e socket.
os.close();
br.close();
socket.close();
Aps compilar o programa com sucesso, execute-o com um nmero de porta disponvel,
e tente contat-lo a partir de um browser. Para fazer isso, digite o endereo IP do seu
servidor em execuo na barra de endereos do seu browser. Por exemplo, se o nome da
sua mquina host.someschool.edu, e o seu servidor roda na porta 6789, ento voc
deve especificar a seguinte URL:
http://host.someschool.edu:6789/
Como o browser precede o nome do arquivo com uma barra, usamos um ponto como
prefixo para que o nome do caminho resultante inicie dentro do diretrio atual.
Agora que temos o nome do arquivo, podemos abrir o arquivo como primeira etapa para
envi-lo ao cliente. Se o arquivo no existir, o construtor FileInputStream() ir
retornar a FileNotFoundException. Em vez de retornar esta possvel exceo e
encerrar a thread, usaremos uma construo try/catch para ajustar a varivel booleana
fileExists
para falsa. A seguir, no cdigo, usaremos este flag para construir uma
contentTypeLine = ?;
entityBody = <HTML> +
<HEAD><TITTLE>Not Found</TITTLE></HEAD> +
<BODY>Not Found</BODY></HTML>;
Enviar
uma
linha
em
branco
para
indicar
fim
das
linhas
de
cabealho.
os.writeBytes(CRLF);
Agora que a linha de status e a linha de cabealho com delimitador CRLF foram
colocadas dentro do trecho de sada no caminho para o browser, hora de fazermos o
mesmo com o corpo da entidade. Se o arquivo requisitado existir, chamamos um
mtodo separado para enviar o arquivo. Se o arquivo requisitado no existir, enviamos a
mensagem de erro codificada em HTML que preparamos.
// Enviar o corpo da entidade.
If (fileExists) {
sendBytes(fis, os);
fis.close();
} else {
os.writeBytes(?);
}
Aps enviar o corpo da entidade, o trabalho neste thread est terminado; ento fechamos
as cadeias e o socket antes de encerrarmos.
10
return text/html;
}
if(?) {
?;
}
of(?) {
?;
}
return application/octet-stream;
}
Est faltando um pedacinho deste mtodo. Por exemplo, nada retornado para arquivos
GIF ou JPEG. Voc mesmo poder adicionar os tipos de arquivo que esto faltando, de
forma que os componentes da sua home page sejam enviados com o tipo de contedo
corretamente especificado na linha de cabealho do tipo de contedo. Para GIFs, o tipo
MIME image/gif e, para JPEGs, image/jpeg.
Isso completa o cdigo para a segunda fase de desenvolvimento do nosso servidor Web.
Tente rodar o servidor a partir do diretrio onde sua home page est localizada e
visualizar os arquivos da home page com o browser. Lembre-se de incluir um
especificador de porta na URL, de forma que o browser no tente se conectar pela porta
80. Quando voc se conectar ao servidor Web em execuo, examine as requisies
GET de mensagens que o servidor Web receber do browser.
11
Neste laboratrio, voc implementar um agente usurio de correio que envia e-mail
para outros usurios. Sua tarefa programar a interao SMTP entre o MUA e o
servidor SMTP local. O cliente prov uma interface grfica de usurio, a qual deve
conter campos para os endereos do remetente e do destinatrio, para o assunto da
mensagem e para a prpria mensagem. A interface de usurio deve ser parecida com:
Com essa interface, quando se quer enviar um e-mail, preciso preencher os endereos
completos do remetente e do destinatrio (exemplo: user@someschool.edu, e no
simplesmente user). Voc poder enviar e-mail para apenas um destinatrio. Tambm
ser necessrio informar o nome (ou endereo IP) do seu servidor de correio local. Veja
Querying the DNS abaixo para mais informaes sobre como obter o endereo do
servidor de correio local.
Quando tiver encerrado a composio do e-mail, pressione Send para envi-lo.
12
O cdigo
O programa consiste de quatro classes:
MailClient
A interface do usurio
Message
A mensagem de e-mail
Envelope
SMTPConnection
Voc precisar completar o cdigo na classe SMTPConnection de modo que no fim voc
tenha um programa capaz de enviar e-mail para qualquer destinatrio. O cdigo para a
classe SMTPConnection est no fim desta pgina. O cdigo para outras trs classes
fornecido nesta pgina.
Os locais onde voc dever completar o cdigo esto marcados com comentrios
/* Fill in */.
13
Cdigos de resposta
Para o processo bsico de envio de mensagem, necessrio implementar apenas uma
parte do SMTP. Neste laboratrio, voc precisar implementar somente os seguintes
comandos SMTP:
Comando
Cdigo de resposta
DATA
354
HELO
250
MAIL FROM
250
QUIT
221
RCPT TO
250
A tabela acima tambm lista os cdigos de resposta aceitos para cada um dos comandos
SMTP que voc precisar implementar. Para simplificar, pode-se presumir que qualquer
outra resposta do servidor indica um erro fatal e aborta o envio da mensagem. Na
realidade, o SMTP distingue entre erros transientes (cdigos de resposta 4xx) e
permanentes (cdigos de resposta 5xx), e o remetente autorizado a repetir os
comandos que provocaram um erro transiente. Veja o Apndice E da RFC-821 para
mais detalhes.
Alm disso, quando voc abre uma conexo para o servidor, ele ir responder com o
cdigo 220.
Nota: A RFC-821 permite o cdigo 251 como resposta ao comando RCPT TO para
indicar que o destinatrio no um usurio local. Voc pode verificar manualmente com
o comando telnet o que o seu servidor SMTP local responde.
Dicas
A maior parte do cdigo que voc precisar completar similar ao cdigo que voc
escreveu no laboratrio de servidor Web. Voc pode us-lo aqui para ajud-lo.
Para facilitar o debug do seu programa, no inclua logo de incio o cdigo que abre o
socket, mas as seguintes definies: fromServer e toServer. Desse modo, seu
programa envia os comandos para o terminal. Atuando como um servidor SMTP, voc
precisar fornecer os cdigos de resposta correto. Quando seu programa funcionar,
adicione o cdigo que abre o socket para o servidor.
14
As linhas para abrir e fechar o socket, por exemplo, as linhas connection = ... no
construtor e a linha connection.close() na funo close(), foram excludas como
comentrios por default.
Comearemos completando a funo parseReply(), que ser necessria em vrios
lugares. Na funo parseReply(), voc deve usar a classe StringTokenizer para
analisar as strings de resposta. Voc pode converter uma string em um inteiro da
seguinte forma:
Int i = Integer.parseInt(argv[0]);
Voc no precisa se preocupar com os detalhes, desde que as excees neste laboratrio
sejam usadas apenas para sinalizar um erro, e no para dar informao detalhada sobre o
que est errado.
Exerccios opcionais
Tente fazer os seguintes exerccios opcionais para tornar seu programa mais sofisticado.
Para estes exerccios, ser necessrio modificar outras classes tambm (MailClient,
Message, e Envelope).
15
Mltiplos destinatrios. At este ponto, o programa permite apenas enviar email a um nico destinatrio. Modifique a interface de usurio para incluir um
campo Cc e modifique o programa para enviar e-mail a dois destinatrios. Para
aumentar o desafio, modifique o programa para enviar e-mail a um nmero
arbitrrio de destinatrios.
Maior verificao de erros. O cdigo fornecido presume que todos os erros que
ocorrem durante a conexo SMTP so fatais. Adicione cdigo para distinguir
entre erros fatais e no fatais e adicione um mecanismo para sinaliz-los ao
usurio. Cheque o RFC para saber o significado dos diferentes cdigos de
resposta. Este exerccio pode requerer grandes modificaes nas funes
send( ), sendCommand( ) e parseReply( ).
Consultando o DNS
O DNS (Domain Name System) armazena informaes em registros de recursos. Os
nomes para mapeamentos de endereo IP so armazenados nos registros de recursos do
tipo A (Address). Os registros do tipo NS (NameServer) guardam informaes sobre
servidores de nomes e os registros do tipo MX (Mail eXchange) dizem qual servidor
est manipulando a entrega de correio no domnio.
O servidor que voc precisa encontrar o que est manipulando o correio para o
domnio da sua escola. Primeiramente, preciso encontrar o servidor de nomes da
escola e ento consult-lo pelo MX-hospedeiro. Supondo que voc est na Someschool
e que seu domnio someschool.edu, voc pode fazer o seguinte:
1. Encontrar o endereo de um servidor de nomes para o domnio do maior nvel .edu
(NS query)
2. Consultar o servidor de nomes de .edu , que buscar o servidor de nomes do domnio
someschool.edu
(NS query)
16
(MX query)
nslookup host
NS-query
MX-query
A resposta para o MX-query pode conter mltiplas contas de e-mail. Cada uma delas
precedida por um nmero que ser o valor preferencial para este servidor. Valores
menores de preferncia indicam servidores preferidos de modo que voc possa usar o
servidor com o valor mais baixo de preferncia.
SMTPConnection.java
Este o cdigo para a classe SMTPConnection que voc precisar completar. O cdigo
para as outras trs classes fornecido neste ponteiro.
Import java.net.*;
Import java.io.*;
Import java.util.*;
/**
* Abre uma conexo SMTP para o servidor de correio e envia um e-mail.
*
*/
public class SMTPConnection {
/* O socket para o servidor */
private Socket connection;
17
Estamos
conectados?
Usamos
close()
para
determinar
que
fazer.*/
private boolean isConnected = false;
/* Crie um objeto SMTPConnection. Crie os sockets e os
trechos associados. Inicie a conexo SMTP. */
public SMTPConnection(Envelope envelope) throws IOException {
// connection = /* Preencher */;
fromServer = /* Preencher */;
toServer =
/* Preencher */;
/* Preencher */
/* Ler uma linha do servidor e verificar se o cdigo de
resposta 220. Se no for, lance uma IOException. */
/* Preencher */
/* SMTP handshake. Precisamos do nome da mquina local.
Envie o comando handskhake do SMTP apropriado. */
String localhost = /* Preencher */;
sendCommand( /* Preencher*/ );
isConnected = true;
}
/* Envie a mensagem. Escreva os comandos SMTP corretos na ordem
correta. No verifique de erros, apenas lance-os ao chamador. */
public void send(Envelope envelope) throws IOException {
/* Preencher */
/* Envie todos os comandos necessrios para enviar a mensagem.
Chame o sendCommand() para fazer o trabalho sujo. No apanhe a
exceo lanada pelo sendCommand(). */
/* Preencher */
}
/* Feche a conexo. Primeiro, termine no nvel SMTP, ento feche o
socket. */
18
Cheque
se
cdigo
de
resposta
do
servidor
mesmo
do
19
Para a resposta a este comando, pode haver vrios servidores de correio que entregam email para as caixas de correio no domnio someschool.edu. Suponha que o nome de um
deles mx1.someschool.edu. Nesse caso, o seguinte comando estabelecer a conexo
TCP a este servidor de correio. (Note que a porta nmero 25 especificada na linha de
comando.)
telnet mx1.someschool.edu 25
Neste ponto, o programa telnet permitir a voc entrar com os comando SMTP e exibir
as respostas do servidor de correio. Por exemplo, a seqncia de comandos a seguir
envia um e-mail da Alice para o Bob.
HELO alice
MAIL FROM: <alice@crepes.fr>
RCPT TO: <bob@someschool.edu>
DATA
SUBJECT: hello
Hi Bob, Hows the weather? Alice.
20
.
QUIT
Isso significa que voc incluir em seu cdigo os detalhes da mensagem de e-mail que
voc est tentando enviar.
Aqui est um esqueleto do cdigo que voc precisar para escrever:
import java.io.*;
import java.net.*;
public class EmailSender
{
public static void main(String() args) throws Exception
{
// Estabelecer uma conexo TCP com o servidor de correio.
21
22
Cdigo do servidor
O cdigo a seguir implementa por completo o servidor de Ping. Voc precisar compilar
e executar este cdigo. Estude-o cuidadosamente, pois ele ir ajud-lo a escrever seu
cliente de Ping.
import.java.io.*;
import.java.net.*;
import.java.util.*;
/*
* Servidor para processar as requisies de Ping sobre UDP.
*/
public class PingServer
{
private static final doubl LOSS_RATE = 0.3;
private static final int AVERAGE_DELAY = 100; //milliseconds
public static void main(String[]args) throws Exception
{
// Obter o argumento da linha de comando.
23
if (args.length !=1) {
System.out.pritln(Required arguments: port);
return;
}
int port = Integer.parseInt(args[0]);
// Criar um gerador de nmeros aleatrios para uso em simulao
de perda de pacotes e atrasos na rede.
Random random = new Random();
// Criar um socket de datagrama para receber e enviar pacotes UDP
atravs da porta especificada na linha de comando.
DatagramSocket socket = new DatagramSocket(port);
// Loop de processamento.
while(true);
//
Criar
um
pacote
de
datagrama
para
comportar
pacote
UDP // de chegada.
DatagramPacket request = new DatagramPacket(new
byte[1024],1024);
// Bloquear at que o hospedeiro receba o pacote UDP.
Socket.receive(request);
// Imprimir os dados recebidos.
printData(request);
// Decidir se responde, ou simula perda de pacotes.
if(random.nextDouble() < LOSS_RATE) {
System.out.println(Reply not sent.);
Continue;
}
// Simular o atraso da rede.
Thread.sleep((int)(random.nextDouble) * 2 * AVERAGE_DELAY));
// Enviar resposta.
InetAddress clientHost = request.getAddress();
Int clientPort = request.getPort();
Byte[]buf = request.getData();
DatagramPacket reply = new DatagramPacket(buf, buf.length,
clientHost, clientPort);
24
Socket.send(reply);
System.out.println(Reply sent.);
}
}
/*
* Imprimir o dado de Ping para o trecho de sada padro.
*/
private static void printData(DatagramPacket request) throws
Exception
{
// Obter referncias para a ordem de pacotes de bytes.
byte[] buf = request.getData();
// Envolver os bytes numa cadeia de entrada vetor de bytes, de
modo que voc possa ler os dados como uma cadeia de bytes.
ByteArrayInputStream bais = new ByteArrayInputstream(buf);
// Envolver a cadeia de sada do vetor bytes num leitor de
cadeia de entrada, de modo que voc possa ler os dados como uma
cadeia de caracteres.
InputStreamReader isr = new InputStreamReader(bais);
// Envolver o leitor de cadeia de entrada num leitor com
armazenagem, de modo que voc possa ler os dados de caracteres
linha a linha. (A linha uma seqncia de caracteres
terminados por alguma combinao de \r e \n.)
BufferedReader br = new BufferedReader(isr);
// O dado da mensagem est contido numa nica linha, ento leia
esta linha.
String line = br.readLine();
// Imprimir o endereo do hospedeiro e o dado recebido dele.
System.out.println(
Received from +
request.getAddress().getHostAddress()+
: +
new String(line));
25
}
}
O servidor fica num loop infinito de escuta pela chegada de pacotes UDP. Quando um
pacote chega, o servidor simplesmente envia o dado encapsulado de volta para o cliente.
Perda de pacotes
O UDP prov aplicaes com servio de transporte no confivel, pois as mensagens
podem se perder pela rede devido a um overflow na fila do roteador ou por outras
razes. Em contraste a isso, o TCP fornece aplicaes com um servio de transporte
confivel, e cada pacote perdido retransmitido at que ele seja recebido com sucesso.
Aplicaes que usam o UDP para comunicao precisam implementar alguma
segurana separadamente no nvel de aplicao (cada aplicao pode implementar uma
poltica diferente, de acordo com necessidades especficas).
Devido ao fato de a perda de pacotes ser rara, ou at mesmo inexistente, em uma rede
tpica, o servidor neste laboratrio injeta perda artificial para simular os efeitos da perda
de pacotes na rede. O servidor possui um parmetro LOSS_RATE, que determina qual a
porcentagem de pacotes deve ser perdida.
O servidor tambm possui outro parmetro, AVERAGE_DELAY, que usado para
simular o atraso de transmisso ao enviar um pacote pela Internet. Voc deve ajustar o
AVERAGE_DELAY com um valor positivo quando o cliente e o servidor forem estar
na mesma mquina, ou quando as mquinas estiverem muito perto fisicamente na rede.
Voc pode ajustar o AVERAGE_DELAY em 0 (zero) para encontrar o tempo de
transmisso verdadeiro dos seus pacotes.
26
onde port o nmero da porta que o servidor escuta. Lembre que voc deve usar um
nmero de porta maior do que 1024, pois apenas os processos executando no modo root
(administrador) possuem privilgio de usar portas menores que 1024.
Nota: Se voc obtiver um erro de classe no encontrada quando executar o comando
acima, voc precisar dizer para o Java olhar no diretrio atual para resolver as
referncias de classe. Nesse caso, os comandos so:
java classpath . PingServer port
completo debug do seu cdigo, voc deve ver como sua aplicao se comunica atravs
da rede com um servidor de Ping sendo executado por um outro membro da classe.
Exerccios opcionais
Quando voc terminar de escrever seu cdigo, pode tentar resolver os seguintes
exerccios.
1) No ponto atual, o programa calcula o tempo de transmisso de cada pacote e os
imprime individualmente. Modifique isso para corresponder ao modo de funcionamento
do programas de Ping padres. Voc dever informar os RTTs mnimo, mximo e
mdio. (fcil)
2) O programa bsico envia um novo Ping imediatamente quando recebe uma resposta.
Modifique-o de modo que ele envie exatamente 1 Ping por segundo, similar ao modo
como programas de Ping padres funcionam. Dica: Use as classes Timer e TimerTask
em java.util. (difcil)
3) Desenvolva duas novas classes, ReliableUdpSender e ReliableUdpReceiver, que
sero usadas para enviar e receber dados de maneira confivel sobre UDP. Para fazer
isso, voc precisar projetar um protocolo (como o TCP) em que o destinatrio dos
dados envia acknowledgements de volta ao remetente para indicar que o dado foi
recebido. Voc pode simplificar o problema apenas provendo um transporte
unidirecional de dados de aplicao do remetente ao destinatrio. Como seus
28
29
Neste laboratrio, voc desenvolver um pequeno servidor Web proxy que tambm ser
capaz de fazer cache de pginas Web. Este ser um servidor proxy bem simples, que
apenas entender requisies GET simples, mas ser capaz de manipular todos os tipos
de objetos, no apenas pginas HTML, mas tambm imagens.
Cdigo
O cdigo est dividido em trs classes:
ProxyCache
as requisies.
HttpRequest
do cliente.
HttpResponse
Seu trabalho ser completar o proxy de modo que ele seja capaz de receber requisies,
encaminh-las, ler as respostas e retorn-las aos clientes. Voc precisar completar a
classes ProxyCache, HttpRequest, e HttpResponse. Os lugares onde voc precisar
preencher o cdigo estaro marcados com /* Preencher */. Cada lugar pode exigir uma
ou mais linhas de cdigo.
Nota: Conforme ser explicado abaixo, o proxy utiliza DataOutputStreams para
processar as respostas dos servidores. Isso ocorre porque as respostas so uma mistura
de texto e dados binrios, e a nica cadeia de entrada em Java que permite trabalhar
com ambos ao mesmo tempo a DataOutputStream. Para obter o cdigo a ser
compilado, voc deve usar o argumento deprecation para o compilador, conforme
segue:
javac deprecation *.java
30
Executando o proxy
Para executar o proxy faa o seguinte:
java ProxyCache port
onde port o nmero da porta que voc quer que o proxy escute pela chegada de
conexes dos clientes.
Funcionalidades do proxy
O proxy funciona da seguinte forma:
1. O proxy escuta por requisies dos clientes.
2. Quando h uma requisio, o proxy gera um novo thread para tratar a requisio e
cria um objeto HttpRequest que contm a requisio.
3. O novo thread envia a requisio para o servidor e l a resposta do servidor dentro
de um objeto HttpResponse.
4. O thread envia a resposta de volta ao cliente requisitante.
Sua tarefa completar o cdigo que manipula o processo acima. A maior parte dos erros
de manipulao em proxy muito simples, e o erro no informado ao cliente. Quando
ocorrem erros, o proxy simplesmente pra de processar a requisio e o cliente
eventualmente recebe uma resposta por causa do esgotamento da temporizao.
31
Alguns browsers tambm enviam uma requisio por vez, sem usar conexes paralelas.
Especialmente em pginas com vrias imagens, pode haver muita lentido no
carregamento delas.
Caching
Realizar o caching das respostas no proxy fica como um exerccio opcional, pois isso
demanda uma quantidade significativa de trabalho adicional. O funcionamento bsico
do caching descrito a seguir:
1. Quando o proxy obtm uma requisio, ele verifica se o objeto requisitado est no
cache; se estiver, ele retorna o objeto do cach, sem contatar o servidor.
2. Se o objeto no estiver no cache, o proxy traz o objeto do servidor, retorna-o ao
cliente e guarda uma cpia no cache para requisies futuras.
Na prtica, o proxy precisa verificar se as respostas que possui no cache ainda so
vlidas e se so a resposta correta requisio do cliente. Voc pode ler mais sobre
caching e como ele tratado em HTTP na RFC-2068. Para este laboratrio, isto
suficiente para implementar a simples poltica acima.
Dicas de programao
A maior parte do cdigo que voc precisar escrever est relacionada ao processamento
de requisies e respostas HTTP, bem como o tratamento de sockets Java.
Um ponto notvel o processamento das respostas do servidor. Em uma resposta HTTP,
os cabealhos so enviados como linhas ASCII, separadas por seqncias de caracteres
CRLF. Os cabealhos so seguidos por uma linha vazia e pelo corpo da resposta, que
pode ser dados binrios no caso de imagens por exemplo.
O Java separa as cadeias de entrada conforme elas sejam texto ou binrio. Isso apresenta
um pequeno problema neste caso. Apenas DataInputstreams so capazes de tratar texto
e binrio simultaneamente; todas as outras cadeias so puro texto (exemplo:
BufferedReader), ou puro binrio (exemplo: BufferedInputStream), e mistur-los no
mesmo socket geralmente no funciona.
32
geralmente
funciona,
mas
compilador
ver
mtodo
Exerccios opcionais
Quando voc terminar os exerccios bsicos, tente resolver os seguintes exerccios
opcionais.
1. Melhor tratamento de erros. No ponto atual, o proxy no possui nenhum tratamento
de erro. Isso pode ser um problema especialmente quando o cliente requisita um objeto
que no est disponvel, desde que a resposta usual 404 Not Found no contenha
corpo de resposta e o proxy presuma que existe um corpo e tente l-lo.
2. Suporte para o mtodo POST. O proxy simples suporta apenas o mtodo GET.
Adicione o suporte para POST incluindo o corpo de requisio enviado na requisio
POST.
3. Adicione caching. Adicione o funcionamento simples de caching descrito acima. No
preciso implementar nenhuma poltica de substituio ou validao. Sua
implementao deve ser capaz de escrever respostas ao disco (exemplo: o cache) e
traz-las do disco quando voc obtiver um encontro no cache. Para isso, voc precisa
implementar alguma estrutura interna de dados no proxy para registrar quais objeto
esto no cache e onde eles se encontram no disco. Voc pode colocar essa estrutura de
dados na memria principal; no necessrio faz-la persistir aps processos de
desligamento.
33
Viso geral
Neste laboratrio, voc escrever o cdigo de nvel de transporte de envio e recepo,
implementando um simples protocolo de transferncia de dados confivel. H duas
verses deste laboratrio: a verso protocolo bit alternante e a verso Go-Back-N. O
laboratrio ser divertido, visto que sua implementao ir diferir um pouco do que
seria exigido numa situao do mundo real.
Como voc provavelmente no possui mquinas standalone (com um OS que pode ser
modificado), seu cdigo precisar ser executado num ambiente de hardware/software
simulado. No entanto, a interface de programao fornecida para suas rotinas, por
exemplo, o cdigo que poderia chamar suas entidades de cima e de baixo bem
prximo do que feito num ambiente UNIX atual. (Na verdade, as interfaces de
software descritas neste exerccio so muito mais realistas do que remetentes e
destinatrios de loop infinito que muitos textos descrevem.) Interrupo/acionamento de
temporizadores sero tambm simulados, e interrupes feitas pelo temporizador faro
com que seu temporizador manipule rotinas a serem ativadas.
34
Essa declarao, e todas as outras estruturas de dados e rotinas de emulador, bem como
rotinas de ponta (exemplo: aquelas que voc precisa completar) esto no arquivo
prog2.c, descrito mais tarde. Sua entidade de envio receber dados em blocos de 20bytes da camada 5; sua entidade de recepo dever entregar blocos de 20 bytes de
dados recebidos corretamente para a camada 5 do lado destinatrio.
A unidade de dados que trafega entre suas rotinas e a camada de rede o pacote, que
declarado como:
struct pkt {
int seqnum;
int acknum;
int checksum;
char payload[20];
};
Suas rotinas iro preencher o campo carga til do dado da mensagem vinda da camada
5. Os outros campos da mensagem sero usados por seus protocolos para assegurar
entrega confivel.
As rotinas que voc escrever esto detalhadas abaixo. Conforme dito acima, tais
procedimentos no mundo real seriam parte do sistema operacional e chamados por
outros procedimentos no sistema operational.
A_output(message), onde message a estrutura do tipo msg, contendo dados que
sero enviados para o lado B. Esta rotina ser chamada sempre que a camada superior
do lado (A) tenha uma mensagem a ser enviada. Este o trabalho do seu protocolo para
assegurar que os dados em tal mensagem sejam entregues em ordem, e corretamente,
para a camada superior do lado destinatrio.
A_input(packet), onde packet a estrutura do tipo pkt. Esta rotina ser chamada
sempre que um pacote enviado pelo lado B (exemplo: como resultado de um
tolayer3()
35
Interfaces de software
Os procedimentos descritos acima so aqueles que voc ir escrever. As rotinas a seguir
foram escritas e podem ser chamadas pelas suas rotinas:
starttimer(calling_entity, increment), em que calling_entity ser 0 (para
acionar o temporizador do lado A) ou 1 (para acionar o temporizador do lado B), e
increment
36
com calling_entity igual a 1 (entrega para o lado B). Ao chamar esta rotina, os
dados passaro para a camada 5.
37
para
seus
procedimentos.
Para
obter
este
programa,
acesse
http://gaia.cs.umass.edu/kurose/transport/prog2.c.
Este laboratrio pode ser feito em qualquer mquina com suporte a C. Ele no faz uso
de caractersticas UNIX. (Voc pode simplesmente copiar o arquivo prog2.c em
qualquer mquina e sistema operacional de sua escolha).
Recomendamos-lhe que tenha em mos uma listagem do cdigo, um documento de
projeto e uma sada de amostra. Para sua sada de amostra, seus procedimentos podem
imprimir uma mensagem sempre que um evento ocorrer no seu remetente ou
destinatrio (a chegada de uma mensagem/pacote, ou uma interrupo de temporizador)
bem como qualquer ao tomada como resposta. Voc pode querer ter uma sada para
uma execuo at o ponto (aproximadamente) quando 10 mensagens tiverem sido
confirmadas (ACK) corretamente pelo destinatrio, uma probabilidade de perda de 0,1,
38
unidirecional de dados do lado A para o lado B, com tamanho de janela igual a 8. Seu
protocolo dever usar mensagens ACK e NACK. Consulte a verso protocolo bit
alternante acima para informaes sobre como obter e emulador de rede.
altamente recomendvel que voc implemente primeiro o laboratrio mais fcil (bit
alternante) e ento estenda seu cdigo para implementar o mais difcil (Go-Back-N).
Acredite, isso no ser perda de tempo! No entanto, algumas novas consideraes para
o seu cdigo Go-Back-N (que no se aplicam ao protocolo bit alternante) so:
A_output(message), onde message uma estrutura do tipo msg contendo dados para
serem enviados ao lado B.
Agora sua rotina A_output() ser chamada algumas vezes quando houver pendncias,
mensagens no confirmadas no meio implicando a necessidade de voc ter um buffer
para mensagens mltiplas em seu remetente. Voc tambm precisar do buffer devido
natureza do Go-Back-N: algumas vezes seu remetente ser chamado mas no ser capaz
de enviar a nova mensagem porque ela cai fora da janela.
Ento voc dever se preocupar em armazenar um nmero arbitrrio de mensagens.
Voc pode ter um valor finito para o nmero mximo de buffers disponveis em seu
remetente (para 50 mensagens) e pode simplesmente abortar (desistir e sair) se todos os
50 buffers estiverem em uso de uma vez (Nota: usando os valores acima, isso nunca
dever acontecer). No mundo real, naturalmente, deveria haver uma soluo mais
elegante para o problema de buffer finito.
A_timerinterrupt() Esta rotina ser chamada quando o temporizador de A expirar
(gerando uma interrupo de temporizador). Lembre que voc possui apenas um
39
Dicas teis
Soma de verificao. Voc pode usar qualquer soluo de soma de verificao que
quiser. Lembre que o nmero de seqncia e o campo ack tambm podem ser
corrompidos. Sugerimos uma soma de verificao como o do TCP, que consiste na
soma dos valores (inteiro) dos campos de seqncia e do campo ack adicionada soma
caracter por caracter do campo carga til do pacote (exemplo: trate cada caracter como
se ele fosse um inteiro de 8 bits e apenas adicione-os juntos).
Note que qualquer estado compartilhado entre suas rotinas deve estar na forma de
variveis globais. Note tambm que qualquer informao que seus procedimentos
precisam salvar de uma invocao para a prxima tambm deve ser uma varivel global
(ou esttica). Por exemplo, suas rotinas precisam manter uma cpia de um pacote para
uma possvel retransmisso. Nesse caso, seria provavelmente uma boa idia uma
estrutura de dados ser uma varivel global no seu cdigo. Note, no entanto, que se uma
das suas variveis usada pelo seu lado remetente, essa varivel no deve ser acessada
pela entidade do lado destinatrio, pois, no mundo real, a comunicao entre entidades
conectadas apenas por um canal de comunicao no compartilha variveis.
40
H uma varivel global flutuante chamada time, que voc pode acessar de dentro do
seu cdigo para auxili-lo com diagnsticos de mensagens.
COMECE SIMPLES. Ajuste as probabilidades de perda e corrupo para zero e
teste suas rotinas. Melhor ainda, projete e implemente seus procedimentos para o caso
de nenhuma perda ou corrupo. Primeiro, faa-as funcionar; ento trate o caso de uma
dessas probabilidades no ser zero e, finalmente, de ambas no serem zero.
Debugging. Recomendamos que voc ajuste o nvel de trace para 2 e coloque vrios
printf em seu cdigo enquanto faz a depurao de seus procedimentos.
Nmeros aleatrios. O emulador gera perda de pacotes e erros usando um gerador de
nmeros aleatrios. Nossa experincia passada que geradores de nmeros aleatrios
podem variar bastante de uma mquina para outra. Voc pode precisar modificar o
cdigo do gerador de nmeros aleatrios no emulador que estamos fornecendo. Nossas
rotinas do emulador possuem um teste para ver se o gerador de nmeros aleatrios em
sua mquina funcionar com o nosso cdigo. Se voc obtiver uma mensagem de erro:
provvel que o gerador de nmeros aleatrios em sua mquina seja diferente
daquele que este emulador espera. Favor verificar a rotina jimsrand() no cdigo
do emulador. Desculpe.
ento voc saber que precisa olhar como os nmeros aleatrios so gerados na rotina
jimsrand(); veja os comentrios nessa rotina.
Q&A
Quando pensamos neste laboratrio em nosso curso de introduo de redes, os
estudantes enviaram vrias questes. Se voc estiver interessado em v-las, acesse:
http://gaia.cs.umass.edu/kurose/transport/programming_assignment_QA.htm.
41
Viso geral
Neste laboratrio, voc escrever um conjunto distribudo de procedimentos que
implementam um roteamento de vetor de distncias assncrono distribudo para a rede
mostrada na Figura Lab.4-1.
42
num pacote de rotina vindo de algum outro n i contm o custo do caminho mais curto
de i para todos os outros ns da rede. rtupdate0() usa estes valores recebidos para
atualizar sua prpria tabela de distncia (como especificado pelo algoritmo de vetor de
distncias). Se o seu prprio custo mnimo para outro n mudar como resultado da
atualizao, o n 0 informa a todos os vizinhos diretamente conectados sobre essa
mudana em custo mnimo enviando para eles um pacote de rotina. Ressaltamos que no
algoritmo de vetor de distncias, apenas os ns diretamente conectados iro trocar
pacotes de rotina. Portanto, os ns 1 e 2 se comunicam entre si, mas os ns 1 e 3 no.
Conforme vimos em aula, a tabela de distncia dentro de cada n a principal estrutura
de dados usada pelo algoritmo de vetor de distncias. Voc achar conveniente declarar
a tabela de distncia como uma disposio 4-por-4 de ints, onde a entrada [i,j] na
tabela de distncia no n 0 o custo atual do n 0 para o n i pelo vizinho direto j.
Se 0 no estiver diretamente conectado ao j, voc pode ignorar essa entrada.
Usaremos a conveno de que o valor inteiro 999 infinito.
A Figura Lab.4-2 fornece uma viso conceitual do relacionamento dos procedimentos
dentro do n 0.
Rotinas similares so definidas para os ns 1, 2 e 3. Portanto, voc escrever 8
procedimentos ao todo: rtinit0(), rtinit1(), rtinit2(), rtinit3(),
rtupdate0(), rtupdate1(), rtupdate2(), rtupdate3()
43
44
impresso similares esto definidas para voc nos arquivos node1.c, node2.c e
node3.c.
procedimentos
rtinit0(),
rtinit1(),
rtinit2(),
rtinit3()
(cujo formato est descrito acima) dentro do meio. O meio entregar os pacotes em
ordem e sem perda para o destinatrio especfico. Apenas ns diretamente conectados
podem se comunicar. O atraso entre o remetente e o destinatrio varivel (e
desconhecido).
Quando voc compilar seus procedimentos e meus procedimentos juntos e executar o
programa resultante, dever especificar apenas um valor relativo ao ambiente de rede
simulado:
Tracing. Ajustar um valor de tracing de 1 ou 2 imprimir informaes teis sobre o
que est acontecendo dentro da emulao (exemplo: o que ocorre com pacotes e
temporizadores). Um valor de tracing de 0 desliga esta opo. Um valor maior do que
2 exibir todos os tipos de mensagens de uso prprio para depurao do meu emulador.
Um valor igual a 2 pode ser til para voc fazer o debug do seu cdigo. Mantenha em
mente que implementaes reais no provem tais informaes sobre o que est
acontecendo com seus pacotes.
Tarefa bsica
Voc escrever os procedimentos rtinit0(), rtinit1(), rtinit2(), rtinit3()
e
rtupdate0(),
rtupdate1(),
rtupdate2(),
rtupdate3()
que
juntos
visvel fora de um dado arquivo C (exemplo: qualquer varivel global que voc definir
em node0.c. pode ser acessada somente dentro do node0.c). Isso o forar a cumprir
convenes que deveriam ser adotadas se voc fosse executar os procedimentos em
45
node1.c, node2.c, node3.c. Voc pode adquirir uma cpia do arquivo prog3.c em:
http://gaia.cs.umass.edu/kurose/network/prog3.c.
Esta tarefa pode ser feita em qualquer mquina que tenha suporte a C. Ela no utiliza
caractersticas UNIX.
Como sempre, a maior parte dos instrutores espera que voc possua uma lista de
cdigos, um documento de projeto e uma sada de amostra.
Para sua sada de amostra, seus procedimentos devem imprimir uma mensagem sempre
que seus procedimentos rtinit0(), rtinit1(), rtinit2(), rtinit3() ou
rtupdate0(),
rtupdate1(),
rtupdate2(),
rtupdate3()
forem chamados,
identidade do remetente do pacote de rotina que est sendo passado para sua rotina, se a
tabela de distncia for, ou no, atualizada, o contedo da tabela de distncia (voc pode
usar minha rotina de impresso) e uma descrio de todas as mensagens enviadas para
os ns vizinhos como resultado de cada atualizao da tabela de distncia.
A sada de amostra deve ser uma listagem de sada com um valor de TRACE igual a 2.
Destaque a tabela de distncia final produzida em cada n. Seu programa ser executado
at que no haja mais nenhum pacote de rotina em trnsito na rede. Nesse ponto, o
emulador terminar.
Tarefa avanada
Voc escrever dois procedimentos, rtlinkhandler0(int linkid, int newcost) e
rtlinkhandler1(int linkid, int newcost),
custo do link entre 0 e 1 mudar. Essas rotinas devem ser definidas nos arquivos node0.c
e node1.c, respectivamente. As rotinas levaro o nome (id) do n vizinho no outro lado
do link cujo custo foi mudado, e o novo custo do link. Note que quando o custo de um
link muda, suas rotinas devero atualizar a tabela de distncia e podem (ou no) precisar
enviar pacotes de roteamento atualizados aos ns vizinhos.
46
Para completar a parte avanada da tarefa, voc precisar mudar o valor da constante
LINKCHANGES (linha 3 no prog3.c) para 1. Para sua informao, o custo do link
ser alterado de 1 para 20 no tempo 10000 e ento retornar para 1 no tempo 20000.
Suas rotinas sero invocadas nesses instantes.
altamente recomendvel que voc implemente primeiro a tarefa bsica e ento estenda
seu cdigo para implementar a tarefa avanada.
Q&A
Quando pensamos neste laboratrio em nosso curso de introduo de redes, os
estudantes enviaram vrias questes. Se voc estiver interessado em v-las, acesse:
http://gaia.cs.umass.edu/kurose/network/programming_assignment_QA.htm.
47
O cdigo
Neste laboratrio, voc implementar um servidor de streaming vdeo e cliente que se
comunica usando o protocolo de fluxo contnuo em tempo real (RTSP) e envia dados
usando o protocolo de tempo real (RTP). Sua tarefa implementar o protocolo RTSP no
cliente e implementar o empacotamento RTP no servidor.
Forneceremos o cdigo que implementa o protocolo RSTP no servidor, o
desempacotamento RTP no cliente e trataremos de exibir o vdeo transmitido. Voc no
precisa mexer neste cdigo.
Classes
Existem quatro classes nesta tarefa.
Client
Esta classe implementa o cliente e a interface de usurio que voc usar para
enviar comandos RTSP e que ser utilizada para exibir o vdeo. Abaixo vemos
como a interface. Voc dever implementar as aes que so tomadas quando
os botes so pressionados.
Server
Esta classe implementa o servidor que responde s requisies RTSP e
encaminha o vdeo de volta. A interao RTSP j est implementada e o servidor
chama as rotinas na classe RTPpacket para empacotar os dados de vdeo. Voc
no precisa mexer nesta classe.
RTPpacket
Esta classe usada para manipular os pacotes RTP. Ela possui rotinas separadas
para tratar os pacotes recebidos no lado cliente que j dado e voc no precisa
modific-lo (mas veja os Exerccios opcionais). Voc dever completar o
primeiro construtor desta classe para implementar o empacotamento RTP dos
dados de vdeo. O segundo construtor usado pelo cliente para desempacotar os
dados. Voc no precisa modific-lo tambm.
48
VideoStream
Esta classe usada para ler os dados de vdeo do arquivo em disco. Voc no
precisa modificar esta classe.
Executando o cdigo
Aps completar o cdigo, voc pode execut-lo da seguinte forma:
Primeiro, inicie o servidor com o comando:
java Server server_port
onde server_port a porta onde seu servidor escuta as conexes RTSP que chegam. A
porta RTSP padro a 554, mas voc deve escolher um nmero de porta maior que
1024.
Ento, inicie o cliente com o comando:
java Client server_name server_port video_file
49
Voc pode enviar comandos RTSP para o servidor pressionando os botes. Uma
interao normal RTSP acontece assim:
1. O cliente envia SETUP. Esse comando usado para ajustar os parmetros de
sesso e de transporte.
2. O cliente envia PLAY. Isso inicia a reproduo.
3. O cliente pode enviar PAUSE se ele quiser pausar durante a reproduo.
4. O cliente envia TEARDOWN. Isso termina a sesso e fecha a conexo.
O servidor sempre responde a todas as mensagens que o cliente envia. Os cdigos de
resposta so exatamente os mesmos do HTTP. O cdigo 200 indica que a requisio foi
bem-sucedida. Neste laboratrio, voc no precisa implementar nenhum outro cdigo de
resposta. Para mais informaes sobre o RTSP, veja a RFC-2326.
1. Cliente
Sua primeira tarefa implementar o RTSP do lado cliente. Para fazer isso, voc deve
completar as funes que so chamadas quando o usurio clica nos botes da interface
50
de usurio. Para cada boto na interface, h uma funo manipuladora do cdigo. Voc
deve implementar as seguintes aes em cada funo manipuladora.
Quando o cliente iniciado, ele tambm abre o socket RTSP para o servidor. Use este
socket para enviar todas as requisies RTSP.
SETUP
Crie um socket para receber os dados RTP e ajustar o tempo de expirao no
socket para 5 milissegundos.
Envie uma requisio SETUP para o servidor. Voc deve inserir o cabealho de
Transporte onde voc especificar a porta para o socket de dados RTP que voc
criou.
Leia a resposta do servidor e analise o cabealho de Sesso na resposta para obter
o ID da sesso.
PLAY
Envie uma requisio PLAY. Voc deve inserir o cabealho de sesso e usar o ID
de sesso fornecido na resposta ao SETUP. No coloque cabealho de Transporte
nesta requisio.
Leia a resposta do servidor.
PAUSE
Envie uma requisio PAUSE. Voc deve inserir o cabealho de Sesso e usar o ID
de sesso fornecido na resposta ao SETUP. No coloque cabealho de Transporte
nesta requisio.
Leia a resposta do servidor.
TEARDOWN
Envie uma requisio TEARDOWN. Voc deve inserir o cabealho de Sesso e
usar o ID de sesso fornecido na resposta ao SETUP. No preciso colocar
cabealho de Transporte neste requisio.
Leia a resposta do servidor.
51
Nota: Voc deve inserir o cabealho CSeq em cada requisio que voc enviar. O valor
do cabealho CSeq um numero que ser incrementado de 1 a cada requisio que voc
enviar.
Exemplo
Aqui est uma interao de amostra entre cliente e servidor. As requisies dos clientes
so marcadas com C: e as respostas dos servidores com S:. Neste laboratrio, tanto o
cliente quanto o servidor so bem simples. Eles no precisam ter rotinas de anlise
sofisticadas e esperam sempre encontrar os campos do cabealho na ordem que voc
ver abaixo, ou seja, numa requisio, o primeiro cabealho o CSeq, e o segundo ou
o de Transporte (para SETUP) ou o de Sesso (para todas as outras requisies). Na
resposta, CSeq novamente o primeiro e de Sesso o segundo.
C: SETUP movie.Mjpeg RTSP/1.0
C: CSeq: 1
C: Transport: RTP/UDP; client_port= 25000
S: RTSP/1.0 200 OK
S: CSeq: 1
S: Session: 123456
C: PLAY movie.Mjpeg RTSP/1.0
C: CSeq: 2
C: Session: 123456
S: RTSP/1.0 200 OK
S: CSeq: 2
S: Session: 123456
C: PAUSE movie.Mjpeg RTSP/1.0
C: CSeq: 3
C: Session: 123456
S: RTSP/1.0 200 OK
S: CSeq: 3
S: Session: 123456
C: PLAY movie.Mjpeg RTSP/1.0
52
C: CSeq: 4
C: Session: 123456
S: RTSP/1.0 200 OK
S: CSeq: 4
S: Session: 123456
C: TEARDOWN movie.Mjpeg RTSP/1.0
C: CSeq: 5
C: Session: 123456
S: RTSP/1.0 200 OK
S: CSeq: 5
S: Session: 123456
Estado do cliente
Uma das diferenas entre HTTP e RTSP que no RTSP cada sesso possui um estado.
Neste laboratrio, voc precisar manter o estado do cliente atualizado. O cliente muda
de estado quando ele recebe uma resposta do servidor de acordo com o seguinte
diagrama.
2. Servidor
No servidor, voc precisar implementar o empacotamento dos dados de vdeo em
pacotes RTP. Para isso, ser necessrio criar o pacote, ajustar os campos no cabealho
do pacote e copiar a carga til (exemplo: um quadro de vdeo) dentro do pacote.
Quando o servidor recebe a requisio PLAY do cliente, ele aciona um temporizador
que ativado a cada 100ms. Nesses tempos, o servidor ler um quadro de vdeo do
53
54
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|
CC
|M|
PT
sequence number
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
timestamp
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
....
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
O diagrama acima est na ordem de byte de rede (tambm conhecido como big-endian).
A Java Virtual Machine usa a mesma ordem de byte, ento voc no precisa transformar
seu cabealho de pacote na ordem de byte de rede.
Para mais detalhes sobre RTP, veja a RFC-1889.
Manipulando os bits
Aqui esto alguns exemplos de como ajustar e verificar bits individuais ou grupo de
bits. Note que no formato do cabealho do pacote RTP, os menores nmeros de bit se
referem a maiores ordens de bits, ou seja, o bit nmero 0 de um byte 2^7, e o bit
nmero 7 1 (ou 2^0). Nos exemplos abaixo, os nmeros de bit se referem aos nmeros
no diagrama acima.
Como o campo header da classe RTPpacket um vetor do tipo byte, voc precisar
ajustar o cabealho de um byte por vez, que um grupo de 8 bits. O primeiro byte
possui os bits 0-7, o segundo byte possui os bits 8-15, e assim por diante. Em Java, um
int tem 32 bits ou 4 bytes.
Para ajustar o nmero n na varivel mybyte do tipo byte:
mybyte = mybyte | 1 << (7 n);
55
Note que foo deve ter um valor que possa ser expresso com 2 bits, ou seja, 0, 1, 2 ou 3.
Para copiar um foo inteiro de 16-bits em 2-bytes, b1 e b2:
b1 = foo >> 8;
b2 = foo & 0xFF;
Aps fazer isso, b1 ter 8 bits de maior ordem de foo e b2 ter 8 bits de menor ordem
de foo.
Voc pode copiar um inteiro de 32-bits em 4-bytes de maneira similar.
Se voc no se sente confortvel com o ajuste de bits, pode encontrar mais informaes
no Java Tutorial.
Exemplo de bit
Suponha que desejamos preencher o primeiro byte do cabealho do pacote RTP com os
seguintes valores:
V=2
P=0
X=0
CC = 3
Em binrio, isso poderia ser representado como
1 0 | 0 | 0 | 0 0 1 1
V=2
CC = 3
2^7 . . . . . . . 2^0
Exerccios opcionais
Em vez do servidor normal fornecido a voc, use a classe chamada FunkyServer
(faa tambm o download da classe FunkyServer$1.class), por exemplo, execute-o com
java FunkyServer server_port.
Apndice
Formato do MJPEG (Motion JPEG) proprietrio do laboratrio.
Neste laboratrio, o servidor encaminha um vdeo codificado com um formato de
arquivo proprietrio MJPEG. Este formato armazena o vdeo como concatenao de
imagens codificadas em JPEG, com cada imagem sendo precedida por um cabealho de
5-bytes que indica o tamanho em bits da imagem. O servidor analisa o bitstream do
arquivo MJPEG para extrair as imagens JPEG no caminho. O servidor envia as imagens
ao cliente em intervalos peridicos. O cliente ento exibe as imagens JPEG individuais
conforme elas vo chegando do servidor.
57