Buscar

Sistemas Distribuidos Capitulo 3

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 26 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Comunicação Entre Processos
Comunicação entre processos está no cerne de todo sistema distribuído. A comunicação em sistemas distribuídos é sempre baseada em troca de mensagens de baixo nível. Expressar comunicação por meio de troca de mensagens é mais difícil do que usar primitivas baseadas em memória compartilhada. Sistemas distribuídos modernos frequentemente consistem em milhares de processos espalhados por uma rede cuja comunicação não é confiável, como a Internet. A menos que sejam oferecidas ferramentas de comunicação mais convenientes, o desenvolvimento de aplicações distribuídas em grande escala é extremamente difícil.
Em muitas aplicações distribuídas, a comunicação não segue o padrão bastante restrito da interação cliente-servidor. Nesses casos, é mais adequado pensar em termos de mensagens.
Protocolos em Camadas
Devido à ausência de memória compartilhada, toda comunicação em sistemas distribuídos é baseada no envio e recebimento de mensagens.
Se A enviar um texto em português codificado segundo o código de caracteres EBCDIC e B estiver esperando um texto em inglês codificado em ASCII, a comunicação não será ótima. Para que a troca de informações possa ocorrer de maneira efetiva vários acordos precisam ser estabelecidos.
Para ficar mais fácil lidar com os vários níveis e questões envolvidos em comunicação, a International Organization for Standardization (ISO) desenvolveu um modelo de referência que identifica claramente os vários níveis envolvidos, dá-lhes nomes padronizados e indica qual nível deve fazer tal serviço. Esse modelo é denominado modelo de referência para interconexão de sistemas abertos (Open Systems Interconnection Reference Model), usualmente abreviado para modelo OSI. Os protocolos que foram desenvolvidos como parte do modelo OSI nunca foram amplamente utilizados. Contudo o modelo subjacente em si mostrou ser bastante útil para entender redes de computadores.
O modelo OSI é projetado para permitir que sistemas abertos se comuniquem. Um sistema aberto é o que está preparado para se comunicar com qualquer outro sistema aberto usando regras padronizadas que regem o formato, o conteúdo e o significado das mensagens recebidas. Essas regras estão formalizadas em protocolos. Se um grupo de computadores quiser se comunicar por uma rede, todos eles têm de concordar com os protocolos que serão utilizados. É feita uma distinção entre dois tipos gerais de protocolos.
Nos protocolos orientados a conexão, antes de trocar dados o remetente e o receptor estabelecem explicitamente uma conexão. Após concluírem, devem liberar a conexão. Nos protocolos sem conexão não é preciso estabelecer nada antecipadamente. O remetente apenas transmite a mensagem quando estiver pronto.
Camadas do Modelo OSI
O RM-OSI (Reference Model for Open Systems Interconnection – Modelo de Referência para Interconexão de Sistemas Abertos) é mostrado na figura abaixo. Ele é um modelo de 7 camadas baseado em uma proposta desenvolvida pela ISO (International Organization for Standardization) como um primeiro passo na direção da padronização internacional dos protocolos usados nas diversas camadas. O modelo OSI trata da interconexão de sistemas abertos, ou seja, sistemas que estão abertos à comunicação com outros sistemas.
 
O modelo OSI em si não é uma arquitetura de rede, pois não especifica os serviços e os protocolos que devem ser usados em cada camada. Ele apenas informa o que cada camada deve fazer. No entanto, a ISO criou padrões para todas as camadas, embora eles não pertençam ao modelo de referência propriamente dito.
Camada Física
A camada física trata da transmissão bruta de bits através de um canal de comunicação, sem se preocupar com o seu significado. O projeto da rede deve garantir que, quando um lado envia um bit, o outro lado o receba corretamente. As questões mais comuns são a quantidade de volts a ser usada para representar um bit 1 e um bit 0, a quantidade de tempo que um bit deve durar, o fato de a transmissão poder ser ou não realizada nas duas direções, a forma como a conexão inicial será estabelecida e de que maneira ela será encerrada, a quantidade de pinos que o conector da rede precisará e de que maneira eles serão utilizados, etc. As questões dizem respeito às interfaces mecânicas, elétricas e procedurais e ao meio de transmissão físico, que fica abaixo da camada física.
Camada de Enlace de Dados
A principal tarefa da camada de enlace de dados é transformar um canal de transmissão de bits de dados bruto em uma linha que pareça livre dos erros de transmissão não detectados na camada de rede. Para tal, a camada de enlace de dados divide os dados de entrada em quadros de dados (que em geral têm algumas centenas ou milhares de bytes), transmite-os sequencialmente e processa os quadros de reconhecimento transmitidos pelo receptor.
Cabe à camada de enlace de dados criar e reconhecer os limites do quadro. Para o reconhecimento dos limites podem ser utilizados quatro métodos.
Contagem de caracteres: o cabeçalho informa o tamanho do quadro.
Caracteres delimitadores e transparência de caracteres: caracteres especiais são utilizados para indicar o início e o fim do quadro. Para evitar confusão de aparecerem delimitadores nos dados são inseridos caracteres especiais.
Sequências especiais de bits: são utilizados flags para delimitar os quadros. Para evitar sequência igual nos dados é criado o bit stuffing.
Violação de código: utilizado em redes onde a codificação dos bits traz redundâncias como, por exemplo, Manchester, que determina o bit pela direção da transição no meio do período do relógio.
Ruídos na linha podem destruir completamente um quadro. Nesse caso, a camada de enlace de dados da máquina de origem deverá retransmitir o quadro. No entanto, várias transmissões do mesmo quadro criam a possibilidade de existirem quadros repetidos, especialmente no caso de um quadro de reconhecimento enviado pelo receptor ao transmissor ser perdido. Cabe à camada de enlace de dados resolver os problemas causados pelos quadros repetidos, perdidos e danificados. Ela pode, ainda, oferecer diferentes classes de serviço para a camada de rede.
Outra função da camada de enlace de dados é implementar algum mecanismo de controle de fluxo para impedir que um transmissor rápido seja dominado por um receptor lento.
Nas redes de difusão a camada de enlace de dados precisa ainda controlar o acesso ao canal compartilhado. Esse problema é resolvido por uma subcamada especial denominada subcamada de acesso ao meio.
Camada de Rede
A camada de rede controla como os pacotes são roteados da origem para o destino. As rotas podem se basear em tabelas estáticas que raramente são alteradas, podem ser determinadas no início de cada conversação ou podem ser altamente dinâmicas, sendo determinadas para cada pacote a fim de refletir a situação atual da rede.
Se houver muitos pacotes na sub-rede eles utilizarão o mesmo caminho, provocando engarrafamentos. O controle de congestionamento pertence à camada de rede.
A camada de rede também é responsável pelo endereçamento das máquinas.
Em redes que trabalham com unidades de dados de diferentes tamanhos no nível de enlace de dados pode ser necessário realizar a fragmentação e a remontagem dos pacotes. A camada de rede é a responsável por esta tarefa.
A camada de rede pode interligar redes com diferentes protocolos de enlace de dados.
Camada de Transporte
A função básica da camada de transporte é aceitar dados da camada superior, dividi-los em unidades menores (caso seja necessário), passá-los para a camada de rede e garantir que todas as unidades cheguem corretamente à outra extremidade. Ela deve isolar os níveis superiores de erros como chegada fora de ordem dos pacotes ou até mesmo a perda ou a duplicação de um pacote.
A camada de transporte determina o tipo de serviço que será oferecido à camada acima. O tipo de conexão de transporte mais comum é o canal ponto a ponto sem erros, que libera mensagens ou bytes na ordem em que eles são enviados. Outros tipospossíveis de serviço de transporte são as mensagens isoladas sem garantia em relação à ordem de entrega e à difusão de mensagens para muitos destinos. O tipo de serviço é determinado quando a conexão é estabelecida.
A camada de transporte é uma camada fim a fim, que liga a origem ao destino. Nas camadas inferiores os protocolos são trocados entre máquinas vizinhas.
Muitos hosts são multiprogramados, possuindo várias conexões com outros hosts. Desta forma, é preciso criar algum mecanismo que determine a qual conexão uma mensagem pertence. A multiplexação de várias conexões deve ser feita de forma transparente pela camada de transporte para as camadas superiores.
Além da multiplexação, a camada de transporte pode realizar também o splitting, que é o aumento da vazão distribuindo uma conexão de transporte por várias conexões de rede simultaneamente.
Também cabe à camada de transporte estabelecer e encerrar conexões.
Camada de Sessão
A camada de sessão permite que os usuários de diferentes máquinas estabeleçam sessões entre eles. As sessões têm por finalidade manter a funcionalidade das aplicações do host mesmo que haja problemas nas camadas inferiores. Uma sessão pode, por exemplo, ser usada para permitir que um usuário estabeleça um login com um sistema remoto ou transfira um arquivo entre dois hosts e não seja necessário refazer o login ou reiniciar a transferência por causa de uma eventual queda de conexão.
Um dos serviços de sessão é o gerenciamento de token. Para alguns protocolos, é necessário que ambos os lados não executem a mesma operação ao mesmo tempo. A camada de sessão oferece tokens para serem trocados, fazendo com que determinadas operações só possam ser executadas pelo lado que está mantendo o token.
Outro serviço que a camada de sessão oferece é a sincronização. São inseridos pontos de sincronização no fluxo de dados de forma que se a conexão for perdida não seja necessário retransmitir todos os dados novamente, mas apenas aqueles enviados após o último ponto de sincronização.
Camada de Apresentação
A camada de apresentação executa determinadas funções solicitadas com muita frequência, oferecendo uma solução geral para todas elas em vez de deixar tal responsabilidade a cargo de cada usuário. Ao contrário das camadas inferiores, que estão interessadas em tornar confiável o processo de movimentação de bits de uma extremidade a outra, a camada de apresentação se preocupa com a sintaxe e a semântica das informações transmitidas.
Um exemplo típico de um serviço da camada de apresentação é a codificação de dados conforme o padrão estabelecido. Hosts têm diferentes códigos para representar strings e valores numéricos. Para permitir que hosts com diferentes representações se comuniquem, as estruturas de dados trocadas podem ser definidas de uma forma abstrata, juntamente com a codificação padrão a ser usada durante a conexão. A camada de apresentação gerencia essas estruturas de dados abstratas e converte a representação utilizada pelo host para a representação padrão da rede, e vice-versa.
Outros exemplos de serviços que podem ser oferecidos pela camada de apresentação são a criptografia e a compressão de dados.
Camada de Aplicação
É a camada que oferece aos usuários acesso à pilha de protocolos OSI. Ela contém uma série de protocolos necessários ao funcionamento de uma rede como, por exemplo, terminais virtuais, transferência de arquivos, correio eletrônico, etc.
É na camada de aplicação que são executados os processos dos usuários.
Transmissão de Dados no Modelo OSI
A figura abaixo mostra como os dados podem ser transmitidos através do modelo OSI. Um processo que deseja enviar dados para um receptor passa os dados para a camada de aplicação que, em seguida, anexa o cabeçalho da aplicação e transmite o item resultante para a camada de apresentação.
 
A camada de apresentação inclui um cabeçalho ao item a ser enviado e passa o resultado para a camada de sessão. A camada de apresentação não identifica qual trecho dos dados transmitidos a ela é o cabeçalho da camada de aplicação e quais são os verdadeiros dados do usuário.
O processo é repetido até os dados alcançarem a camada física, onde eles são realmente transmitidos para o host de recepção. Na recepção, os diversos cabeçalhos são excluídos um a um conforme a mensagem se propaga pelas camadas.
Embora a transmissão de dados propriamente dita seja vertical, cada camada é programada como se fosse horizontal. Quando a camada de transporte do transmissor, por exemplo, obtém uma mensagem da camada de sessão, ela anexa um cabeçalho de transporte e a envia à camada de transporte do receptor.
Protocolos de Middleware
O Middleware é uma aplicação que reside logicamente, na maioria das vezes, na camada de aplicação, mas que contém muitos protocolos de uso geral que justificam suas próprias camadas.
Alguns dos protocolos de comunicação de middleware poderiam pertencer à camada de transporte, mas há razões específicas para mantê-los em um nível mais alto. Um sistema de middleware pode oferecer diferentes protocolos (adaptáveis), cada um, por sua vez, usando diferentes protocolos de transporte, mas oferecendo uma única interface.
A adoção dessa abordagem de camadas resulta em um modelo de referência para comunicação ligeiramente adaptado. Em comparação com o modelo OSI, as camadas de sessão e apresentação foram substituídas por uma única camada de middleware que contém protocolos independentes de aplicação.
Problemas de Interligação em Rede para Sistemas Distribuídos
As primeiras redes de computadores foram projetadas para atender a alguns poucos requisitos de aplicações em rede relativamente simples, como a transferência de arquivos, login remoto, correio eletrônico e newsgroups. O desenvolvimento de sistemas distribuídos, com suporte para programas aplicativos distribuídos, acesso a arquivos compartilhados e outros recursos, estabeleceu um padrão de desempenho mais alto para atender às necessidades das aplicações interativas.
Mais recentemente, acompanhando o crescimento, a comercialização e o emprego de novos usos da Internet, surgiram requisitos de confiabilidade, escalabilidade, mobilidade, segurança e qualidade de serviço mais rigorosos.
Desempenho
Os parâmetros de desempenho de rede que têm principal interesse para sistemas distribuídos são aqueles que afetam a velocidade e a vazão com que as mensagens podem ser transferidas entre dois computadores interligados. São eles: latência e taxa de transferência de dados ponto a ponto.
 A latência é o tempo decorrido após uma operação de envio ser executada e antes que os dados comecem a chegar em seu destino. Aqui, estamos considerando apenas a latência da rede.
A taxa de transferência de dados é a vazão com que os dados podem ser transferidos entre dois computadores em uma rede, uma vez que a transmissão tenha começado. É normalmente medida em bits por segundo (bps).
Como resultado, o tempo exigido para que uma rede transfira uma mensagem contendo uma certa largura de bits entre dois computadores é:
Tempo de transmissão da mensagem = latência + tamanho/taxa de transferência
A equação acima é válida para mensagens cuja largura não ultrapasse o limite máximo determinado pela tecnologia de rede empregada para seu envio. Mensagens maiores precisam ser segmentadas (ou fragmentadas), e o tempo de transmissão é a soma dos tempos dos segmentos (fragmentos).
A taxa de transferência de uma rede é determinada principalmente por suas características físicas, enquanto a latência é determinada principalmente pelas sobrecargas do software, pelos atrasos de roteamento e por um fator estatístico dependente da carga da rede, proveniente do conflito de acesso aos canais de transmissão. Em sistemas distribuídos, é comum a transferência de muitas mensagens de pequeno tamanho entre processos; portanto, na determinação do desempenho, a latência frequentemente assume uma importância igual ou maior que a taxa de transferência.
A largura de banda de uma rede é o volume total de tráfegoque pode ser transferido na rede em um determinado período. Na maioria das redes de longa distância, as mensagens podem ser transferidas simultaneamente em diferentes canais, e a largura de banda total do sistema não apresenta relacionamento direto com a taxa de transferência.
Considere o desempenho de uma comunicação cliente-servidor. O tempo necessário para a transmissão de uma mensagem de requisição (curta) e para o recebimento de sua resposta, também curta, em uma rede local pouco carregada (incluindo as cargas de processamento) é de cerca de meio milissegundo. Compare com o tempo inferior a um microssegundo exigido para uma aplicação invocar uma operação sobre um objeto armazenado na memória local. Assim, o tempo exigido para acessar recursos compartilhados em uma rede local permanece cerca de mil vezes maior do que o tempo exigido para acessar recursos armazenados em memória local. Porém, a latência e a largura de banda da rede frequentemente superam o desempenho do disco rígido; o acesso por rede a um servidor Web, ou a um servidor de arquivos local que mantêm em cache uma grande quantidade de arquivos frequentemente utilizados, pode equivaler, ou superar, o acesso aos arquivos armazenados em um disco rígido local.
Na Internet, as latências entre a ida e a volta de mensagens estão na faixa dos 5 a 500 ms, com uma média de 20 a 200 ms, dependendo da distância. Portanto os pedidos transmitidos pela Internet são de 10 a 100 vezes mais lentos do que nas redes locais mais rápidas. A maior parte dessa diferença de tempo é consequência dos atrasos em roteadores e da disputa por circuitos de comunicação da rede.
Escalabilidade
As redes de computadores são uma parte indispensável da infraestrutura das sociedades modernas. O crescimento tem sido tão rápido e diversificado que fica difícil encontrar estatísticas atualizadas e confiáveis. O potencial futuro tamanho da Internet é proporcional à população do planeta. É realista esperar que ela vá incluir vários bilhões de nós e centenas de milhões de computadores.
Esses números indicam as mudanças futuras no tamanho e na carga que a Internet deverá manipular. As tecnologias de rede em que ela é baseada não foram projetadas para suportar a atual escala da Internet, mas têm funcionado notavelmente bem. Para tratar a próxima fase de crescimento da Internet, algumas mudanças substanciais nos mecanismos de endereçamento e roteamento estão em andamento. A capacidade da infraestrutura da Internet de suportar esse crescimento dependerá de fatores econômicos para seu uso, em especial das cobranças impostas aos usuários e dos padrões de demanda de comunicação que realmente ocorrerem.
Confiabilidade
Muitos aplicativos são capazes de se recuperar de falhas de comunicação e, assim, não exigem a garantia da comunicação isenta de erros. O subsistema de comunicação não precisa oferecer comunicação totalmente isenta de erros. Frequentemente, a detecção de erros de comunicação e sua correção é melhor realizada por software aplicativo. A confiabilidade da maior parte da mídia de transmissão física é muito alta. Quando ocorrem erros, é normalmente devido a falhas no software presente no remetente ou no destinatário (por exemplo, o computador destino deixa de aceitar um pacote) ou devido a estouros de buffer, em vez de erros na rede.
Segurança
O primeiro nível de defesa adotado pela maioria das organizações é proteger suas redes e os computadores ligados a elas com um firewall. Um firewall cria uma barreira de proteção entre a intranet da organização e o restante da Internet. Seu propósito é proteger os recursos presentes nos computadores de uma organização contra o acesso de usuários ou processos externos e, ao mesmo tempo, controlar o uso dos recursos externos por usuários da própria organização.
Para permitir que os aplicativos distribuídos superem as restrições impostas pelos firewalls, há necessidade de produzir um ambiente de rede seguro, no qual uma ampla variedade de aplicativos distribuídos possa ser implantada, com autenticação fim-a-fim, privacidade e segurança. Essa forma mais refinada e flexível de segurança pode ser obtida com o uso de técnicas de criptografia. Normalmente, ela é aplicada em um nível acima do subsistema de comunicação. As exceções incluem a necessidade de proteger componentes de rede, como os roteadores, contra interferência não autorizada em sua operação e a necessidade de se ter enlaces seguros para dispositivos móveis e nós externos, para permitir sua participação em uma intranet segura. Normalmente tal acesso é implementado por intermédio de uma rede privada virtual (VPN – Virtual Private Network).
Mobilidade
Os dispositivos móveis mudam frequentemente de lugar e são reconectados em diferentes pontos da rede, ou mesmo usados enquanto estão em movimento. As redes sem fio fornecem conectividade para tais dispositivos, mas os esquemas de endereçamento e de roteamento da Internet foram desenvolvidos antes do surgimento desses dispositivos móveis e não são adaptados às suas características de conexão intermitente em diversas sub-redes diferentes. Os mecanismos da Internet foram adaptados e ampliados para suportar mobilidade, mas o crescimento esperado para o uso de dispositivos móveis exigirá ainda mais desenvolvimento.
Qualidade do serviço
Qualidade do serviço é a capacidade de atender a prazos finais ao transmitir e processar fluxos de dados multimídia em tempo real. Isso impõe às redes de computadores novos requisitos importantes. Os aplicativos que transmitem dados multimídia exigem largura de banda garantida e latências limitadas para os canais de comunicação que utilizam. Alguns aplicativos variam sua demanda dinamicamente e especificam uma qualidade de serviço mínima aceitável e uma ótima desejada.
Multicasting
Também conhecida como difusão seletiva.
A maior parte da comunicação em sistemas distribuídos se dá entre pares de processos, mas frequentemente também há necessidade de uma comunicação de um para muitos. Embora isso possa ser simulado por múltiplos envios para vários destinos, é mais dispendioso do que o necessário. Muitas tecnologias de rede suportam a transmissão de uma mensagem para vários destinatários.
Representação Externa de Dados e Empacotamento
As informações armazenadas nos programas em execução são representadas como estruturas de dados, enquanto que as informações presentes nas mensagens são sequências puras de bytes. Independente da forma de comunicação usada, as estruturas de dados devem ser convertidas em uma sequência de bytes (deve ser simplificada) antes da transmissão e reconstruídas na sua chegada. Os dados transmitidos nas mensagens podem corresponder a valores de tipos de dados primitivos diferentes, e nem todos os computadores armazenam tipos de dados primitivos da mesma forma, existem duas variantes para a ordenação de inteiros: big-endian, na qual o byte mais significativo aparece na primeira posição, e a ordem little-endian, na qual ele aparece por último. Outro problema é o conjunto de códigos usado para representar caracteres. A maioria dos aplicativos em sistemas como o UNIX usa codificação de caracteres ASCII, com um byte por caractere, enquanto o padrão Unicode permite a representação de textos em muitos idiomas diferentes e usa dois bytes por caractere.
Um dos métodos a seguir pode ser usado para permitir que dois computadores troquem valores de dados binários:
Os valores são convertidos para um formato externo, acordado antes da transmissão e convertidos para a forma local, na recepção. Se for sabido que os dois computadores são do mesmo tipo, a conversão para o formato externo pode ser omitida.
Os valores são transmitidos no formato do remetente, junto a uma indicação do formato usado, e o destinatário converte os valores, se necessário.
Para suportar RMI ou RPC, todo tipo de dado que possa ser passado como argumento, ou retornado como resultado, deve ser simplificado, e os valores de dados primitivos individuais, representados em um formato comum. Um padrão aceito paraa representação de estruturas de dados e valores primitivos é chamado de representação externa de dados.
Empacotamento (marshalling) é o procedimento de pegar um conjunto de itens de dados e montá-los em uma forma conveniente para transmissão em uma mensagem. Desempacotamento (unmarshalling) é o procedimento inverso de desmontá-los na chegada para produzir um conjunto de itens de dados equivalente no destino. Assim, o empacotamento consiste na transformação de itens de dados estruturados e valores primitivos em uma representação externa de dados. Analogamente, o desempacotamento consiste na geração de valores primitivos a partir de sua representação externa de dados e na reconstrução das estruturas de dados.
Veremos duas alternativas para representação externa de dados e empacotamento:
A representação comum de dados do CORBA.
A XML (Extensible Markup Language).
Como o empacotamento exige a consideração de todos os mínimos detalhes da representação dos componentes primitivos de objetos compostos, esse procedimento é bastante propenso a erros se executado manualmente. A compactação é outro problema que pode ser tratado no projeto de procedimentos de empacotamento gerados automaticamente. No CORBA os tipos de dados primitivos são empacotados em uma forma binária. Na XML os tipos de dados primitivos são representados textualmente.
Outro problema com relação ao projeto de métodos de empacotamento é se os dados empacotados devem incluir informações relativas ao tipo de seu conteúdo. A representação usada pelo CORBA inclui apenas os valores dos objetos transmitidos – nada a respeito de seus tipos. Já os documentos XML podem se referir a conjuntos de nomes (com tipos) definidos externamente, chamados espaços de nomes.
Representação Comum de Dados (CDR) do CORBA
CORBA é a sigla de Common Object Request Broker Architecture, que tem por objetivo a interoperabilidade entre diferentes sistemas computacionais e linguagens de programação através de ORBs, que são estruturas que permitem que os programadores façam chamadas de um computador a outro através de uma rede. O CORBA é definido e padronizado pela OMG (Object Management Group).
O CDR do CORBA pode representar todos os tipos de dados que são usados como argumentos e valores de retorno em invocações a métodos remotos no CORBA. Eles consistem em 15 tipos primitivos, os quais incluem short (16 bits), long (32 bits), unsigned short, unsigned long, float (32 bits), double (64 bits), char, boolean, octet (8 bits) e any (que pode representar qualquer tipo primitivo ou construído), junto a uma variedade de tipos compostos. Cada argumento ou resultado em uma invocação remota é representado por uma sequência de bytes na mensagem de invocação ou resultado.
Para os tipos primitivos o CDR define uma representação para as ordens big-endian e little-endian. Os valores são transmitidos na ordem do remetente, que é especificada em cada mensagem. Se exigir uma ordem diferente, o destinatário a transforma.
Cada tipo primitivo é colocado em um índice na sequência de bytes, de acordo com seu tamanho. Suponha que a sequência de bytes seja indexada a partir de zero. Então, um valor primitivo com tamanho de n bytes (onde n = 1, 2, 4 ou 8) é anexado à sequência, em um índice que é um múltiplo de n no fluxo de bytes. Os valores em ponto flutuante seguem o padrão IEEE. Os caracteres são representados por um código acordado entre cliente e servidor.
Nos tipos construídos ou compostos os valores primitivos que compreendem cada tipo construído são adicionados a uma sequência de bytes, em uma ordem específica, como se vê na figura abaixo.
	Índice na sequência de bytes
	4 bytes
	Observações
	0-3
	5
	Comprimento do string
	4-7
	“Maur”
	Mauro
	8-11
	“o___”
	
	12-15
	6
	Comprimento do string
	16-19
	“Lebl”
	Leblon
	20-23
	“on__”
	
	24-27
	1984
	Unsigned long
A figura mostra uma mensagem no CDR do CORBA contendo três campos de um struct cujos tipos respectivos são: string, string e unsigned long. A figura mostra a sequência de bytes, com quatro bytes em cada linha. A representação de cada string consiste em um valor unsigned long, dando seu comprimento, seguido dos caracteres do string. Assumimos que cada caractere ocupa apenas um byte. Os dados de comprimento variável são preenchidos com zero para que tenha uma forma padrão para permitir a comparação de dados empacotados ou de sua soma de verificação. Cada valor unsigned long, que ocupa quatro bytes, começa em um índice que é múltiplo de quatro.
O tipo de um item de dados não é fornecido na mensagem. Pressupõe-se que o remetente e o destinatário tenham conhecimento comum da ordem e dos tipos dos itens de dados de uma mensagem. Em particular para RMI, ou para RPC, cada invocação de método passa argumentos de tipos específicos e o resultado é um valor de um tipo em particular.
Empacotamento no CORBA
As operações de empacotamento podem ser geradas automaticamente a partir da especificação dos tipos dos itens de dados a serem transmitidos em uma mensagem. Os tipos das estruturas de dados e os tipos dos itens de dados básicos estão descritos no IDL (Interface Definition Language) do CORBA, que fornece uma notação para descrever os tipos dos argumentos e resultados dos métodos RMI. Por exemplo, poderíamos usar o IDL do CORBA para descrever a estrutura de dados na mensagem da figura acima como:
struct Pessoa{
 string nome;
 string local;
 unsigned long ano;
};
O compilador da interface CORBA gera as operações de empacotamento e desempacotamento apropriadas para os argumentos e resultados dos métodos remotos a partir das definições dos tipos de seus parâmetros e resultados.
XML (Extensible Markup Language)
A XML é uma linguagem de marcação que foi definida pelo World Wide Web Consortium (W3C) para uso na Web. O termo linguagem de marcação se refere a uma codificação textual que representa um texto e os detalhes de sua estrutura ou de sua aparência. Tanto a XML quanto a HTML são derivadas da SGML (Standardized Generalized Markup Language). A HTML foi projetada para definir a aparência de páginas Web. A XML foi projetada para elaborar documentos estruturados para a Web. Os itens de dados XML são rotulados com strings de marcação (tags). As tags são usadas para descrever a estrutura lógica dos dados e para associar pares atributo-valor às estruturas lógicas. Na XML as tags estão relacionadas à estrutura do texto que englobam, em contraste com a HTML, na qual as tags especificam como um navegador poderia exibir o texto.
A XML é usada para permitir que clientes se comuniquem com serviços Web e para definir as interfaces e outras propriedades desses mesmos serviços. Também é usada de muitas outras maneiras. Ela é utilizada no arquivamento e na recuperação de sistemas – embora um repositório de arquivos XML possa ser maior do que seu equivalente binário, ele tem a vantagem de poder ser lido em qualquer computador. Outros exemplos do uso da XML incluem a especificação de interfaces com o usuário e a codificação de arquivos de configuração em sistemas operacionais. A XML é extensível, pois os usuários podem definir suas próprias tags, em contraste com a HTML, que usa um conjunto fixo de tags. Entretanto, se um documento XML se destina a ser usado por mais de um aplicativo, os nomes das tags devem ser combinados entre eles.
Algumas representações externas de dados (como o CDR do CORBA) não precisam ser autodescritivas, pois pressupõe-se que o cliente e o servidor que estejam trocando uma mensagem têm conhecimento anterior da ordem e dos tipos das informações que ela contém. A XML foi projetada para ser usada por vários aplicativos, para diferentes propósitos. A capacidade de prover tags, junto com o uso de espaços de nomes para definir o significado das próprias tags, tornou isso possível.
Os documentos XML, sendo textuais, podem ser lidos por seres humanos, embora a maioria dos documentos XML é gerada e lida por software de processamento de XML, mas a capacidade de ler códigoXML pode ser útil quando as coisas dão errado. Além disso, o uso de texto torna a XML independente de qualquer plataforma específica. O uso de uma representação textual, em vez de binária, junto com o uso de tags, torna as mensagens muito maiores, o que faz com que elas exijam tempos de processamento e transmissão maiores, assim como maior espaço de armazenamento. Entretanto os arquivos e as mensagens podem ser compactados, economizando largura de banda durante a transmissão.
Elementos e atributos XML
Podemos representar, em XML, a estrutura pessoa usada para ilustrar o empacotamento no CDR do CORBA como:
<pessoa id="123456789">
 <nome>Mauro</nome>
 <local>Leblon</local>
 <ano>1984</ano>
 <!-- um comentario -->
</person >
Ela mostra que a XML consiste em tags e dados do tipo caractere. Os dados do tipo caractere, por exemplo, Mauro ou 1984, são os dados reais. A estrutura de um documento XML é definida por pares de tags incluídas entre sinais de menor e maior. O leiaute pode ser usado para melhorar a legibilidade.
Um elemento na XML consiste em um conjunto de dados do tipo caractere delimitados por tags de início e de fim correspondentes. Por exemplo, um dos elementos na definição acima consiste no dado Mauro, contido dentro do par de tags <nome>... </nome>. O elemento com a tag <nome> é incluído no elemento com o par de tags <pessoa id=”123456789”>... </pessoa >. A capacidade de um elemento de incluir outro permite a representação de dados hierárquicos, um aspecto muito importante da XML.
Opcionalmente, uma tag de início pode incluir pares de nomes e valores de atributo associados, como em id=”123456789”, conforme mostrado anteriormente. Um nome de atributo é seguido de um sinal de igualdade e um valor de atributo entre aspas. Múltiplos valores de atributo são separados por espaços.
É uma questão de escolha definir quais itens serão representados como elementos e quais serão representados como atributos. Um elemento geralmente é um contêiner para dados, enquanto um atributo é usado para rotular esses dados. Em nosso exemplo, 123456789 poderia ser um identificador usado pelo aplicativo, enquanto nome, local e ano poderiam ser exibidos. Além disso, se os dados contêm subestruturas ou várias linhas, eles devem ser definidos como um elemento. Os atributos servem para valores simples.
Os nomes de tags e atributos na XML geralmente começam com uma letra, mas também podem começar com um sublinhado ou com dois-pontos. Os nomes continuam com letras, dígitos, hífens, sublinhados, dois-pontos ou pontos-finais. Letras maiúsculas e minúsculas são levadas em consideração, isto é, os nomes em XML são case-sensitive. Os nomes que começam com xml são reservados.
Todas as informações nos elementos XML devem ser expressas com dados do tipo caractere, então como representamos elementos criptografados ou hashing de códigos de segurança? A resposta é que eles podem ser representados na notação base64, que utiliza apenas os caracteres alfanuméricos, junto a +, / e =.
Tipos de Comunicação
Para entender as várias alternativas de comunicação que o middleware pode oferecer a aplicações, vemos o middleware como um serviço adicional de computação cliente-servidor, como mostra a figura a seguir.
Com comunicação persistente uma mensagem que foi apresentada para transmissão é armazenada pelo middleware de comunicação durante o tempo que for necessário para entregá-la ao receptor. Nesse caso, o middleware armazenará a mensagem em algum recurso de armazenamento. Assim não é necessário que a aplicação remetente continue em execução após apresentar a mensagem. Da mesma maneira a aplicação receptora não precisa estar em execução no momento em que a mensagem é apresentada.
No caso da comunicação transiente, uma mensagem é armazenada pelo sistema de comunicação somente durante o tempo em que a aplicação remetente e a aplicação receptora estiverem executando. Se o middleware não pode entregar uma mensagem devido a uma interrupção de transmissão, ou se o receptor não estiver ativo no momento considerado, a mensagem será simplesmente descartada. Normalmente os serviços de comunicação de nível de transporte oferecem somente comunicação transiente. Se um repassador não puder entregar uma mensagem ao próximo repassador, ou ao host de destino, ele apenas descarta a mensagem.
Além de persistente ou transiente, a comunicação também pode ser assíncrona ou síncrona. Na comunicação assíncrona um remetente continua sua execução imediatamente após ter apresentado sua mensagem para transmissão. Isso significa que a mensagem é armazenada temporariamente pelo middleware assim que apresentada. Na comunicação síncrona, o remetente é bloqueado até saber que sua requisição foi aceita. Há três pontos em que a sincronização pode ocorrer.
O remetente pode ser bloqueado até que o middleware avise que se encarregará da transmissão da requisição.
O remetente pode sincronizar até que sua requisição seja entregue ao receptor pretendido.
A sincronização pode ocorrer permitindo que o remetente espere até que sua requisição tenha sido totalmente processada, isto é, até o instante em que o receptor retornar uma resposta.
Chamada de Procedimento Remoto
Muitos sistemas distribuídos são baseados em troca explícita de mensagens entre processos. Entretanto os procedimentos send e receive não escondem absolutamente nada da comunicação, o que é importante para obter transparência em sistemas distribuídos.
A solução encontrada foi permitir que processos chamem procedimentos localizados em outras máquinas. Quando um processo na máquina A chama um procedimento na máquina B, o processo chamador em A é suspenso e a execução do procedimento chamado ocorre em B. Informações podem ser transportadas do chamador para o chamado nos parâmetros e podem voltar no resultado do procedimento. Absolutamente nada da troca de mensagens é visível para o programador. Esse método é conhecido como chamada de procedimento remoto (remote procedure call – RPC).
Embora a ideia básica seja simples, existem problemas:
Como o procedimento chamador e o procedimento chamado executam em máquinas diferentes, eles possuem espaços de endereço diferentes.
É necessário passar parâmetros e resultados, o que pode ser complicado, especialmente se as máquinas não forem idênticas.
Qualquer uma das máquinas pode falhar.
Operação Básica de RPC
Chamada de procedimento convencional
Parâmetros podem ser passados por valor ou por referência. Um parâmetro passado por valor é simplesmente copiado para a pilha. Para o procedimento chamado este tipo de parâmetro é apenas uma variável local com valor definido. O procedimento chamado pode modificá-lo, mas tais alterações não afetam o valor original no lado chamador.
Um parâmetro passado por referência é um ponteiro para uma variável, e não o valor da variável. Se o procedimento chamado usar esse parâmetro para armazenar algo, ele modificará a variável no procedimento chamador.
A diferença entre chamadas por valor e chamadas por referência é muito importante para RPC.
Também existe um outro mecanismo de passagem de parâmetro, denominado chamada por copiar/restaurar. Ele consiste em fazer o chamador copiar a variável para a pilha, como na passagem por valor, e então copiá-la de volta após a chamada, sobrescrevendo o valor original do chamador. Sob algumas condições é exatamente o mesmo efeito que chamar por referência, porém em situações como o mesmo parâmetro estar presente várias vezes na lista de parâmetros, a semântica é diferente. Tal mecanismo não é usado em muitas linguagens.
Apêndices de cliente e de servidor
A ideia básica da RPC é fazer com que uma chamada de procedimento remoto pareça o máximo possível uma chamada local. Em outras palavras, queremos que a RPC seja transparente.
Quando um processo em uma máquina remota deve ser chamado, uma versão diferente deste procedimento, denominada apêndice de cliente, é colocada na biblioteca. Ela é chamada como qualquer procedimento local, e depois faz uma chamada aosistema operacional local empacotando os parâmetros em uma mensagem e requisita que essa mensagem seja enviada para o servidor. Em seguida o apêndice de cliente bloqueia a si mesmo até que a resposta volte.
Quando a mensagem chega ao servidor, o sistema operacional do servidor a passa para um apêndice de servidor. Um apêndice de servidor é um pedaço de código que transforma requisições que vêm pela rede em chamadas de procedimento locais. Normalmente o apêndice de servidor estará bloqueado esperando por mensagens que chegam. O apêndice de servidor desempacota os parâmetros da mensagem e então chama o procedimento do servidor da maneira usual.
Do ponto de vista do servidor, é como se ele fosse chamado diretamente pelo cliente. Os parâmetros e endereço de retorno estão todos na pilha à qual pertencem e nada parece fora do normal. O servidor executa seu trabalho e então retorna o resultado ao chamador do modo usual.
Quando a mensagem volta à máquina cliente, o sistema operacional do cliente vê que ela está endereçada ao processo cliente (apêndice de cliente). A mensagem é então copiada para o buffer que está à espera e o processo cliente é desbloqueado. O apêndice de cliente inspeciona a mensagem, desempacota o resultado, o copia para seu chamador e retorna da maneira usual. Quando o chamador retoma o tudo que ele sabe é que seus dados estão disponíveis. Ele não tem ideia de que o trabalho foi realizado remotamente. Todos os detalhes da troca de mensagens ficam ocultos.
Uma chamada de procedimento remoto ocorre nas seguintes etapas:
O procedimento de cliente chama o apêndice de cliente do modo normal.
O apêndice de cliente constrói uma mensagem e chama o sistema operacional local.
O SO do cliente envia a mensagem para o SO remoto.
O SO remoto dá a mensagem ao apêndice de servidor.
O apêndice de servidor desempacota os parâmetros e chama o servidor.
O servidor faz o serviço e retorna o resultado para o apêndice.
O apêndice de servidor empacota o resultado em uma mensagem e chama seu SO local.
O SO do servidor envia a mensagem ao SO do cliente.
O SO do cliente dá a mensagem ao apêndice de cliente.
O apêndice desempacota o resultado e retorna ao cliente.
Passagem de Parâmetros
A função do apêndice de cliente é pegar seus parâmetros, empacotá-los em uma mensagem e enviá-los ao apêndice de servidor.
Passagem de parâmetros por valor
Empacotar parâmetros em uma mensagem é denominado montagem de parâmetros. Como um exemplo muito simples, considere um procedimento remoto, add(i, j), que pega dois parâmetros inteiros, i e j, e retorna sua soma aritmética como resultado.
A chamada para add é mostrada no processo cliente da figura abaixo. O apêndice de cliente toma seus dois parâmetros e os coloca em uma mensagem. Coloca também o nome ou o número do procedimento a ser chamado na mensagem.
Quando a mensagem chega ao servidor, o apêndice a examina para ver qual procedimento é necessário e então faz a chamada apropriada. A chamada propriamente dita do apêndice para o servidor é parecida com a chamada original do cliente.
Quando o servidor termina, o apêndice de servidor retoma novamente o controle, pegando o resultado devolvido pelo servidor e o empacotando em uma mensagem. Essa mensagem é enviada de volta ao apêndice de cliente, que a desempacota para extrair o resultado e retorna o valor para o procedimento de cliente à espera.
Contudo, em um sistema distribuído de grande porte, é comum estarem presentes vários tipos de máquinas. Cada máquina costuma ter sua própria representação para números, caracteres e outros itens de dados.
Passagem de parâmetros por referência
Nas passagens de parâmetro por referência são utilizados ponteiros, que possuem significado apenas dentro do espaço de endereço do processo no qual está sendo usado. Como fazer, então, a passagem de parâmetros por referência? A resposta é: somente com a maior das dificuldades, se é que se consegue.
Uma solução é proibir ponteiros e passagem de parâmetros por referência em geral. Contudo, eles são tão importantes que essa solução é indesejável. Suponha que se saiba qual é o tamanho do vetor. Então, uma estratégia se torna aparente: copiar o vetor para a mensagem e enviá-lo ao servidor. As alterações que o servidor fizer usando o ponteiro afetam diretamente o buffer de mensagem dentro do apêndice de servidor. Quando o servidor termina, a mensagem original pode ser enviada de volta ao apêndice de cliente, que então a copia de volta para o cliente. Na verdade, chamar por referência foi substituída por copiar/restaurar. Embora não seja idêntico, frequentemente é bom o suficiente.
Se os apêndices souberem se o buffer é um parâmetro de entrada ou um parâmetro de saída para o servidor, uma das cópias pode ser eliminada.
Embora as considerações anteriores permitam manipular ponteiros para vetores e estruturas simples, ainda não podemos manipular o caso mais geral de um ponteiro para uma estrutura de dados arbitrária. Alguns sistemas tentam lidar com esse caso realmente passando o ponteiro para o apêndice de servidor e gerando código especial no procedimento de servidor para usar ponteiros. Por exemplo, uma requisição pode ser enviada de volta para que o cliente forneça os dados referenciados.
Especificação de parâmetros e geração de apêndices
Fica claro que ocultar uma chamada de procedimento remoto requer que o chamador e o chamado concordem com o formato das mensagens que trocam e sigam as mesmas etapas quando se tratar de, por exemplo, passar estruturas de dados complexas. Em outras palavras, ambos os lados de uma RPC devem seguir o mesmo protocolo ou a RPC não funcionará corretamente.
Definir o formato da mensagem é um aspecto importante de um protocolo RPC, mas não é suficiente. Também é necessário que o cliente e o servidor concordem com a representação de estruturas de dados simples, como inteiros, caracteres, booleanos e assim por diante.
A única coisa que resta fazer é que o chamador e o chamado concordem com a troca de mensagens propriamente dita. Pode-se decidir usar um serviço de transporte orientado a conexão como TCP/IP. Uma alternativa é usar um serviço não confiável de datagramas e deixar que o cliente e o servidor implementem um esquema de controle de erro como parte do protocolo RPC. Na prática, existem diversas variantes.
Para simplificar interfaces costumam ser especificadas por meio de uma linguagem de definição de interface (Interface Definition Language - IDL). Uma interface especificada em tal IDL é, na sequência, compilada para gerar um apêndice de cliente e um apêndice de servidor, junto com as interfaces adequadas.
A prática mostra que usar uma linguagem de definição de interface simplifica consideravelmente aplicações cliente-servidor baseadas em RPCs. Como é fácil gerar completamente apêndices de cliente e de servidor, todos os sistemas de middleware baseados em RPC oferecem uma IDL para suportar desenvolvimento de aplicações.
RPC Assíncrona
Como em chamadas de procedimento convencionais, quando um cliente chama um procedimento remoto, o cliente bloqueia até que uma resposta seja retornada. Esse comportamento é desnecessário quando não há nenhum resultado a retornar, e só leva ao bloqueio do cliente enquanto ele poderia ter continuado e realizado trabalho útil logo após requisitar o procedimento remoto.
Para suportar essas situações, sistemas RPC podem fornecer facilidades para o que é denominado RPC assíncrona, pela qual um cliente continua imediatamente após emitir a requisição RPC. Com RPCs assíncronas, o servidor envia imediatamente uma resposta de volta ao cliente no momento em que a requisição RPC é recebida e, depois disso, chama o procedimento remoto. A resposta age como um reconhecimento para o cliente de que o servidor vai processar a RPC. O cliente continuará sem bloqueio tão logo tenha recebido o reconhecimento do servidor.
Interação entre cliente e servidor (a) em uma RPC tradicional e (b) em uma RPC assíncrona.
RPCs assíncronas também podem ser úteis quando uma respostavai ser retornada mas o cliente não está preparado para esperar por ela e, enquanto espera, nada faz. Por exemplo, um cliente pode querer buscar antecipadamente os endereços de rede de um conjunto de hospedeiros que espera contatar dentro de pouco tempo. Enquanto um serviço de nomeação está colhendo esses endereços, o cliente pode querer fazer outras coisas. Nesses casos tem sentido organizar a comunicação entre o cliente e o servidor por meio de duas RPCs assíncronas. Na primeira o cliente chama o servidor para lhe entregar uma lista de nomes de hospedeiros que devem ser consultados e continua quando o servidor reconhecer o recebimento dessa lista. A segunda chamada é feita pelo servidor, que chama o cliente para lhe entregar os endereços que encontrou. A combinação de duas RPCs assíncronas às vezes também é denominada RPC assíncrona deferida.
É preciso notar que existem variantes de RPCs assíncronas nas quais o cliente continua executando imediatamente após enviar a requisição ao servidor. Em outras palavras, o cliente não espera por um reconhecimento da aceitação da requisição pelo servidor. Denominamos essas chamadas RPCs de uma via. O problema com essa abordagem é que, quando a confiabilidade não é garantida, o cliente não pode saber, com certeza, se a requisição será ou não processada.
Invocação a método remoto
A RMI (Remote Method Invocation – invocação a método remoto) está intimamente relacionada à RPC, mas é estendida para o mundo dos objetos distribuídos. Na RMI, um objeto chamador pode invocar um método em um objeto potencialmente remoto. Assim como na RPC, os detalhes subjacentes ficam ocultos para o usuário. As características comuns entre a RMI e a RPC são:
Ambas suportam programação com interfaces.
Normalmente, ambas são construídas sobre protocolos de requisição-resposta.
Ambas oferecem um nível de transparência semelhante, isto é, as chamadas locais e remotas empregam a mesma sintaxe, mas as interfaces remotas normalmente expõem a natureza distribuída da chamada subjacente, suportando exceções remotas, por exemplo.
As diferenças a seguir levam a uma maior expressividade na programação de aplicações e serviços distribuídos complexos.
O programador pode usar todo o poder expressivo da programação orientada a objetos no desenvolvimento de software de sistemas distribuídos, incluindo o uso de objetos, classes e herança, e também pode empregar metodologias de projeto orientado a objetos relacionadas e ferramentas associadas.
Complementando o conceito de identidade de objeto dos sistemas orientados a objetos, em um sistema baseado em RMI todos os objetos têm referências exclusivas (sejam locais ou remotos) e tais referências também podem ser passadas como parâmetros, oferecendo, assim, uma semântica de passagem de parâmetros significativamente mais rica do que na RPC.
A questão da passagem de parâmetros é particularmente importante nos sistemas distribuídos. A RMI permite ao programador passar parâmetros não apenas por valor, como parâmetros de entrada ou saída, mas também por referência de objeto. Passar referências é particularmente atraente se o parâmetro for grande ou complexo. Então o lado remoto, ao receber uma referência de objeto, pode acessar esse objeto usando invocação a método remoto, em vez de transmitir o valor do objeto pela rede.
Questões de Projeto para RMI
O principal problema de projeto se relaciona com o modelo de objeto e, em particular, com a transição de objetos para objetos distribuídos. Veremos primeiro o modelo de objeto de imagem única convencional e, depois, consideraremos o modelo de objeto distribuído.
O modelo de objeto
Um programa orientado a objetos consiste em um conjunto de objetos interagindo, cada um dos quais composto de um conjunto de dados e um conjunto de métodos. Um objeto se comunica com outros objetos invocando seus métodos, geralmente passando argumentos e recebendo resultados. Os objetos podem encapsular seus dados e o código de seus métodos. Algumas linguagens permitem que os programadores definam objetos cujas variáveis de instância podem ser acessadas diretamente.
No entanto, para uso em um sistema de objeto distribuído, os dados de um objeto devem ser acessíveis somente por intermédio de seus métodos.
Referências de objeto
Os objetos podem ser acessados por meio de referências de objeto. Por exemplo, em Java, uma variável que parece conter um objeto, na verdade, contém uma referência para esse objeto. Para invocar um método em um objeto, são fornecidos a referência do objeto e o nome do método, junto aos argumentos necessários. O objeto cujo método é invocado é chamado de alvo, de destino e, às vezes, de receptor. As referências de objeto são valores de primeira classe, significando que eles podem, por exemplo, ser atribuídos a variáveis, passados como argumentos e retornados como resultados de métodos.
Interfaces
Uma interface fornece a definição das assinaturas de um conjunto de métodos, sem especificar sua implementação.
Um objeto fornecerá uma interface em particular, caso sua classe contenha código que implemente os métodos dessa interface. Em Java, uma classe pode implementar várias interfaces, e os métodos de uma interface podem ser implementados por qualquer classe. Uma interface também define os tipos que podem ser usados para declarar o tipo de variáveis ou dos parâmetros e valores de retorno dos métodos.
Ações
Em um programa orientado a objetos, a ação é iniciada por um objeto invocando um método em outro objeto. Uma invocação pode incluir informações adicionais (argumentos) necessárias para executar o método. O receptor executa o método apropriado e depois retorna o controle para o objeto que fez a invocação, algumas vezes fornecendo um resultado. A ativação de um método pode ter três efeitos:
O estado do receptor pode ser alterado.
Um novo objeto pode ser instanciado, por exemplo, pelo uso de um construtor.
Outras invocações podem ocorrer nos métodos de outros objetos.
Como uma invocação pode levar a mais invocações a métodos em outros objetos, uma ação é um encadeamento de invocações relacionadas de métodos, cada uma com seu respectivo retorno.
Exceções
Os programas podem encontrar muitos tipos de erros e condições inesperadas, de diversos graus de gravidade. Durante a execução de um método, muitos problemas diferentes podem ser descobertos. Quando os programadores precisam inserir testes em seu código para tratar de todos os casos incomuns ou errôneos possíveis, isso diminui a clareza do caso normal.
As exceções proporcionam uma maneira clara de tratar com condições de erro, sem complicar o código. Além disso, cada cabeçalho de método lista explicitamente como exceções as condições de erro que pode encontrar, permitindo que os usuários desse método as tratem adequadamente.
Pode ser definido um bloco de código para disparar uma exceção, quando surgirem condições inesperadas ou erros em particular. Isso significa que o controle passa para outro bloco de código, que captura a exceção. O controle não retorna para o lugar onde a exceção foi disparada.
Coleta de lixo (garbage collection)
É necessário fornecer uma maneira de liberar o espaço em memória ocupado pelos objetos quando eles não são mais necessários. Uma linguagem que pode detectar automaticamente quando um objeto não está mais acessível, recupera o espaço em memória e o torna disponível para alocação por outros objetos.
Esse processo é chamado de coleta de lixo (garbage collection). Quando uma linguagem não suporta coleta de lixo o programador tem de se preocupar com a liberação do espaço alocado para os objetos. Isso pode ser uma fonte de erros significativa.
Objetos distribuídos
O estado de um objeto consiste nos valores de suas variáveis de instância. No paradigma baseado em objetos, o estado de um programa é dividido em partes separadas, cada uma associada a um objeto. Como os programas baseados em objetos são logicamente particionados, a distribuição física dos objetos em diferentes processos ou computadores de um sistemadistribuído é uma extensão natural.
Os sistemas de objetos distribuídos podem adotar a arquitetura cliente-servidor. Nesse caso, os objetos são gerenciados pelos servidores, e seus clientes invocam seus métodos usando invocação a método remoto (RMI). Na RMI, a requisição de um cliente para invocar um método de um objeto é enviada em uma mensagem para o servidor que gerencia o objeto. A invocação é realizada pela execução de um método do objeto no servidor e o resultado é retornado para o cliente em outra mensagem. Para permitir encadeamentos de invocações relacionadas, os objetos nos servidores podem se tornar clientes de objetos em outros servidores.
O modelo de objeto distribuído
Cada processo contém um conjunto de objetos, alguns dos quais podem receber invocações locais e remotas, enquanto os outros objetos podem receber somente invocações locais. As invocações a métodos entre objetos em diferentes processos, sejam no mesmo computador ou não, são conhecidas como invocações a métodos remotos. As invocações a métodos entre objetos no mesmo processo são invocações a métodos locais.
Referimo-nos aos objetos que podem receber invocações remotas como objetos remotos. Todos os objetos podem receber invocações locais de outros objetos que contenham referências a eles. Os dois conceitos fundamentais a seguir estão no centro do modelo de objeto distribuído:
Referência de objeto remoto: outros objetos podem invocar os métodos de um objeto remoto se tiverem acesso a sua referência de objeto remoto.
Interface remota: todo objeto remoto tem uma interface remota especificando qual de seus métodos pode ser invocado de forma remota.
Referências de objeto remoto
A noção de referência de objeto é estendida para permitir que qualquer objeto que possa receber uma RMI tenha uma referência de objeto remoto. Uma referência de objeto remoto é um identificador que pode ser usado por todo um sistema distribuído para se referir a um objeto remoto único em particular. 
Interfaces remotas
A classe de um objeto remoto implementa os métodos de sua interface remota. Objetos em outros processos só podem invocar os métodos pertencentes à interface remota. Os objetos locais podem invocar os métodos da interface remota, assim como outros métodos implementados por um objeto remoto. As interfaces remotas, assim como todas as interfaces, não têm construtores.
O sistema CORBA fornece uma linguagem de definição de interface (IDL) que é usada para definir interfaces remotas. As classes de objetos remotos e os programas clientes podem ser implementados em qualquer linguagem, como C++, Java ou Python, para a qual esteja disponível um compilador de IDL. Os clientes CORBA não precisam usar mesma linguagem que o objeto remoto para invocar seus métodos de forma remota.
Comunicação Orientada a Mensagem
Chamadas de procedimento remoto e invocações de objeto remoto contribuem para ocultar comunicação em sistemas distribuídos. Em particular, quando não se pode adotar como premissa que o lado receptor está executando no momento em que uma requisição é emitida, são necessários serviços alternativos de comunicação. Da mesma maneira, a natureza síncrona inerente das RPCs, pela qual um cliente é bloqueado até que sua requisição tenha sido processada, às vezes precisa ser substituída por alguma outra coisa.
Comunicação Transiente Orientada a Mensagem
Na comunicação transiente, a mensagem submetida à transmissão é armazenada nos sistemas de comunicação, se e somente se, os processos remetente e destinatário estiverem em execução.
Interface Berkeley
A padronização da interface da camada de transporte foi alvo de especial atenção para permitir que programadores usem todo o seu conjunto de protocolos por meio de um conjunto simples de primitivas. Além disso, interfaces padronizadas facilitam a portabilidade uma aplicação para uma máquina diferente.
Conceitualmente um soquete é um terminal de comunicação para o qual uma aplicação pode escrever dados que devem ser enviados pela rede, e do qual pode ler dados que chegam. Um soquete forma uma abstração sobre o terminal de comunicação propriamente dito que é usado pelo sistema operacional local para um protocolo de transporte específico.
	Primitiva
	Significado
	Socket
	Crie um terminal de comunicação.
	Bind
	Anexe um endereço local a um soquete.
	Listen
	Anuncie a disposição de aceitar conexões.
	Accept
	Bloqueie o chamador até chegar uma requisição de comunicação.
	Connect
	Tente estabelecer uma conexão ativamente.
	Send
	Envie alguns dados pela conexão.
	Receive
	Receba alguns dados pela conexão.
	Close
	Tente estabelecer uma conexão.
Primitivas de socket para TCP/IP.
Em geral, servidores executam as quatro primeiras primitivas, normalmente na ordem dada. Ao chamar a primitiva socket, o chamador cria um terminal de comunicação para um protocolo de transporte específico. Internamente, a criação de um terminal de comunicação significa que o sistema operacional local reserva recursos para atender ao envio e ao recebimento de mensagens para o protocolo especificado.
A primitiva bind associa um endereço local com o soquete recém-criado. Por exemplo, um servidor deve vincular a um soquete seu endereço IP, junto com um número de porta. A vinculação diz ao sistema operacional que o servidor quer receber mensagens somente no endereço e porta especificados.
A primitiva listen é chamada somente no caso de comunicação orientada a conexão. É uma chamada não bloqueadora que permite ao sistema operacional local reservar buffers suficientes para um número especificado de conexões que o chamador está disposto a aceitar.
A chamada accept bloqueia o chamador até chegar uma requisição de conexão. Quando chega uma requisição, o sistema operacional local cria um novo soquete com as mesmas propriedades do original e o retorna ao chamador. Essa abordagem permitirá que o servidor, por exemplo, bifurque um processo que, na sequência, manipulará a comunicação propriamente dita. Enquanto isso, o servidor pode voltar e esperar por uma outra requisição de conexão no soquete original.
Também no lado cliente é preciso, antes de tudo, criar um soquete usando a primitiva socket, mas não é necessário vincular o soquete explicitamente a um endereço local, visto que o sistema operacional pode alocar dinamicamente uma porta quando a conexão for estabelecida.
A primitiva connect requer que o chamador especifique o endereço de nível de transporte para o qual uma requisição de conexão deve ser enviada. O cliente é bloqueado até que uma conexão seja estabelecida com sucesso e, depois disso, ambos os lados podem começar a trocar informações por meio das primitivas send e receive.
Por fim, o fechamento de uma conexão ocorre ao se fazer com que ambos, cliente e servidor, chamem a primitiva close.
Interface de troca de mensagens (MPI)
Com o advento dos multicomputadores de alto desempenho, desenvolvedores começaram a procurar primitivas orientadas a mensagem que lhes permitissem escrever com facilidade aplicações de alta eficiência. Soquetes foram considerados insuficientes porque eles estavam no nível errado de abstração, suportando somente primitivas simples send e receive.
O resultado foi que a maioria das redes de interconexão e multicomputadores de alto desempenho era despachada com bibliotecas de comunicação proprietárias. Essas bibliotecas ofereciam uma profusão de primitivas de comunicação de alto nível eficientes. Todas as bibliotecas eram mutuamente incompatíveis, de modo que, nessa circunstância, os desenvolvedores de aplicação tinham um problema de portabilidade.
A necessidade de ser independente de hardware e de plataforma resultou na definição de um padrão para troca de mensagens, denominado interface de passagem de mensagens (Message Passing Interface – MPI).
A MPI adota a premissa de que a comunicação ocorre dentro de um grupo conhecido de processos. Cada grupo recebe um identificador. Cada processo dentro de um grupo também recebe um identificador local. Um par(groupID, processID) identifica exclusivamente a fonte ou o destinatário de uma mensagem e é usado no lugar de um endereço de nível de transporte. Vários grupos de processos poderão estar envolvidos em um serviço de computação, e todos eles poderão estar em execução ao mesmo tempo.
No cerne da MPI estão primitivas de mensagem para implementar comunicação transiente. As mais intuitivas estão resumidas na tabela abaixo.
	Primitiva
	Significado
	MPI_bsend
	Anexa mensagem de saída a um buffer local de envio.
	MPI _send
	Envia uma mensagem e espera até que seja copiada para buffer local ou remoto.
	MPI _ssend
	Envia uma mensagem e espera até o recebimento começar.
	MPI _sendrecv
	Envia uma mensagem e espera por resposta.
	MPI _isend
	Passa referência para mensagem de saída e continua.
	MPI _issend
	Passa referência para mensagem de saída e espera até o recebimento começar.
	MPI _recv
	Recebe uma mensagem; bloqueia se não houver nenhuma.
	MPI _irecv
	Verifica se há uma mensagem chegando, mas não bloqueia.
Primitivas de troca de mensagens MPI.
Comunicação assíncrona transiente é suportada por meio da primitiva MPI_bsend. O remetente apresenta uma mensagem para transmissão que primeiro é copiada para um buffer local no sistema de execução MPI. Quando a mensagem foi copiada, o remetente continua. O sistema de execução MPI local removerá a mensagem de seu buffer local e providenciará a transmissão assim que um receptor tenha chamado uma primitiva receive.
Há também uma operação de envio bloqueadora, denominada MPI_send. Ela pode bloquear o chamador até que a mensagem especificada tenha sido copiada para o sistema de execução MPI no lado do remetente ou até que o receptor tenha iniciado uma operação de recebimento. A comunicação síncrona, pela qual o remetente bloqueia até que sua requisição seja aceita para processamento, está disponível por intermédio da primitiva MPI_ssend. Por fim, quando um remetente chama MPI_sendrecv, ele envia uma requisição ao receptor e bloqueia até que esse último retorne uma resposta. Basicamente, essa primitiva corresponde a uma RPC normal.
Ambas, MPI_send e MPI_ssend, têm variantes que evitam a cópia de mensagens de buffers de usuários para buffers internos do sistema de execução MPI local. Essas variantes correspondem a uma forma de comunicação assíncrona. Com MPI_ isend, um remetente passa um ponteiro para a mensagem; em seguida o sistema de execução MPI providencia a comunicação. O remetente continua imediatamente. Para evitar sobrescrever a mensagem antes da conclusão da comunicação, a MPI oferece primitivas para verificar conclusão, ou até bloquear, se for preciso. Não é especificado se a mensagem foi realmente transferida para o receptor ou se ela foi simplesmente copiada pelo sistema de execução MPI local para um buffer interno.
De maneira semelhante, com MPI_issend, um remetente também passa somente um ponteiro para o sistema de execução MPI. Quando o sistema de execução indicar que processou a mensagem, o remetente tem a garantia de que o receptor aceitou a mensagem e está trabalhando com ela naquele momento.
A operação MPI_recv é chamada para receber uma mensagem. Ela bloqueia o chamador até chegar uma mensagem. Também há uma variante assíncrona, denominada MPI_irecv, pela qual um receptor indica que está preparado para aceitar uma mensagem. O receptor pode verificar se a mensagem realmente chegou ou não ou bloquear até que uma chegue.
A MPI foi projetada para aplicações paralelas de alto desempenho, o que facilita entender sua diversidade em diferentes primitivas de comunicação.
Comunicação Persistente Orientada a Mensagem
Na comunicação persistente, a mensagem submetida à transmissão é armazenada nos sistemas de comunicação e assim que possível é entregue ao seu destinatário, não sendo necessário que os processos remetente e destinatário estejam em execução.
Chegamos agora a uma classe importante de serviços de middleware orientados a mensagem, conhecidos como sistemas de enfileiramento de mensagens, ou apenas middleware orientado a mensagem (MOM). Sistemas de enfileiramento de mensagens proporcionam suporte extensivo para comunicação assíncrona persistente. A essência desses sistemas é que eles oferecem capacidade de armazenamento de médio prazo para mensagens, sem exigir que o remetente ou o receptor estejam ativos durante a transmissão da mensagem. Uma diferença importante entre a interface Sockets Berkeley e MPI e sistemas de enfileiramento de mensagens é que estes normalmente visam ao suporte de transferências de mensagens que têm permissão de durar minutos em vez de segundos ou milissegundos.
Modelo de enfileiramento de mensagens
A ideia básica que fundamenta um sistema de enfileiramento de mensagens é que aplicações se comunicam inserindo mensagens em filas específicas. Essas mensagens são repassadas por uma série de servidores de comunicação até serem entregues ao destinatário, mesmo que ele não esteja em funcionamento quando a mensagem foi enviada. Em princípio, cada aplicação tem sua própria fila particular para a qual outras aplicações podem enviar mensagens. Uma fila só pode ser lida por sua aplicação associada, mas também é possível que várias aplicações compartilhem uma única fila.
Um aspecto importante de sistemas de enfileiramento de mensagens é que um remetente só tem a garantia de que, a certa altura, sua mensagem será inserida na fila do receptor. Nenhuma garantia é dada sobre quando, nem ao menos se, a mensagem será realmente lida, o que é totalmente determinado pelo comportamento do receptor.
Essa semântica permite comunicação fracamente acoplada em relação ao tempo. Por isso não há necessidade de o receptor estar em execução quando uma mensagem for enviada para sua fila. Da mesma maneira, não há nenhuma necessidade de o remetente estar em execução no momento em que sua mensagem é apanhada pelo receptor. O remetente e o receptor podem executar em completa independência um em relação ao outro.
Um aspecto importante da perspectiva do middleware é que as mensagens sejam adequadamente endereçadas. Na prática, o endereçamento é feito com o fornecimento de um nome exclusivo no âmbito do sistema da fila destinatária. A interface básica oferecida às aplicações pode ser extremamente simples, como mostra a tabela abaixo.
	Primitiva
	Significado
	Put
	Anexe uma mensagem a uma fila especificada.
	Get
	Bloqueie até que a fila especificada esteja não vazia e retire a primeira mensagem.
	Pool
	Verifique uma fila especificada em busca de mensagens e retire a primeira. Nunca bloqueie.
	Notify
	Instale um manipulador a ser chamado quando uma mensagem for colocada em uma fila específica.
Primitivas básicas para um sistema de enfileiramento de mensagens.
A primitiva put é chamada por um remetente para passar uma mensagem ao sistema subjacente, mensagem essa que é anexada à fila especificada. É uma chamada não bloqueadora. A primitiva get é uma chamada bloqueadora pela qual um processo autorizado pode retirar a mensagem que está pendente há mais tempo na fila especificada. O processo é bloqueado somente se a fila estiver vazia. Variações dessa chamada permitem procurar uma mensagem específica na fila. A variante não bloqueadora é dada pela primitiva poll. Se a fila estiver vazia, ou se uma mensagem específica não puder ser encontrada, o processo chamador simplesmente continua.
A maioria dos sistemas de enfileiramento permite, por intermédio da primitiva notify, que um processo instale um manipulador como uma função de chamada de retorno, que é automaticamente invocada sempre que uma mensagem for colocada na fila. Chamadas de retorno também podem ser usadas para iniciar automaticamente um processo que buscará mensagens na fila se nenhum processo estiver em execução naquele instante.
Arquitetura geral de um sistema de enfileiramento de mensagens
Uma das primeiras restrições é que mensagens só podem ser colocadas em filas locais do remetente, isto é, filas na mesma máquina ou, no máximo,em uma máquina próxima, e que possam ser alcançadas de modo eficiente por meio de uma RPC. Essas filas são denominadas filas de fonte. Da mesma maneira, mensagens só podem ser lidas em filas locais. Contudo, uma mensagem colocada em uma fila contém a especificação de uma fila de destino para a qual ela deve ser transferida. Cabe ao sistema de enfileiramento de mensagens a responsabilidade de fornecer filas para remetentes e receptores e providenciar para que as mensagens sejam transferidas da sua fila de fonte para a sua fila de destino.
Um sistema de enfileiramento de mensagens deve manter um mapeamento de filas para localizações de rede. Na prática, isso significa que ele tem de manter bancos de dados de nomes de filas para localizações de rede. Tal mapeamento é completamente análogo à utilização do Sistema de Nomes de Domínio (DNS).
Filas são gerenciadas por gerenciadores de fila. Normalmente, um gerenciador de fila interage diretamente com a aplicação que está enviando ou recebendo uma mensagem. Mas há também gerenciadores especiais de fila que funcionam como roteadores, ou repassadores. Eles repassam mensagens que chegam para outros gerenciadores de fila. Desse modo, um sistema de enfileiramento de mensagens pode crescer gradativamente até uma rede de sobreposição completa de nível de aplicação, por cima de uma rede de computadores existente.
Repassadores podem ajudar a construir sistemas escaláveis de gerenciamento de filas. À medida que as redes de enfileiramento crescem a configuração manual de redes poderá ficar impossível de gerenciar. A solução é adotar esquemas de roteamento dinâmico, como se faz em redes de computadores.
Brokers de mensagens
Uma importante área de aplicação de sistemas de enfileiramento de mensagens é a integração de novas aplicações em um único e coerente sistema distribuído de informações. Integração requer que aplicações possam entender as mensagens que recebem, o que, na prática, significa que as mensagens enviadas pelo remetente devam ter o mesmo formato das mensagens do receptor.
O problema é que cada vez que uma aplicação é adicionada ao sistema que requer um formato diferente de mensagem, cada receptor potencial terá de ser ajustado de modo a produzir aquele formato.
Uma alternativa é concordar com um formato de mensagem comum a todos, como é feito nos protocolos tradicionais de rede. O problema é o nível de abstração no qual esses sistemas operam. Um formato de mensagem comum a todos só tem sentido se o conjunto de processos que usam esse formato realmente tiver muito em comum. Se o conjunto de aplicações que compõe um sistema distribuído de informações apresentar alta diversidade, então o melhor formato comum pode perfeitamente ser nada mais do que uma sequência de bytes.
Embora alguns formatos de mensagem em comum tenham sido definidos para domínios de aplicação específicos, a abordagem geral é aprender a viver com diferentes formatos e tentar providenciar os meios para simplificar ao máximo as conversões. Em sistemas de enfileiramento de mensagens, conversões são manipuladas por nós especiais em uma rede de enfileiramento, conhecidos como brokers de mensagens. Um broker (intermediário) de mensagens age como um gateway de nível de aplicação em um sistema de enfileiramento de mensagens. Sua principal finalidade é converter mensagens que chegam de modo que elas sejam entendidas pela aplicação destinatária. Para um sistema de enfileiramento de mensagens, um broker de mensagens é apenas uma outra aplicação, e não é considerado como uma parte integral do sistema de enfileiramento.
No centro de um broker de mensagens encontra-se um repositório de regras e programas que podem transformar uma mensagem de um tipo em uma mensagem de outro tipo. O problema é definir as regras e desenvolver os programas. A maioria dos produtos de broker de mensagens vem acompanhada de sofisticadas ferramentas de desenvolvimento. Mas, na realidade, o repositório ainda precisa ser preenchido por especialistas.
Exercícios
Qual a vantagem em se construir sistemas com protocolos em camadas?
Em protocolos de camadas, cada camada acrescenta um cabeçalho à mensagem a medida que passa. Seria mais eficiente o acréscimo de um cabeçalho único. Por que isto não é feito?
Em termos de desempenho e facilidade de programação, qual a diferença entre sistemas orientados à conexão e sistemas sem conexão?
Por que o modelo OSI não é considerado uma arquitetura?
No modelo OSI, qual a principal função da camada:
física
enlace de dados
rede
transporte
sessão
apresentação
aplicação
Na concepção de sistemas distribuídos, onde fica localizada a camada de middleware tendo como base as camadas do modelo OSI?
O que é a latência de transmissão?
O tempo de transmissão de uma mensagem é influência pela latência e pela taxa de transmissão da rede. Qual o impacto de cada um para o tempo de transmissão de uma mensagem?
O que se entende por escalabilidade de uma rede?
Para uma rede de transmissão de dados, o que é confiabilidade?
Por que existe a necessidade de se definir uma representação externa de dados?
Para que um sistema distribuído possa trocar informações entre processos é necessário realizar o empacotamento e o respectivo desempacotamento. Qual a finalidade destes procedimentos?
Para que serve o CORBA (Common Object Request Broker Architecture)?
Qual o objetivo do CORBA ao suportar transmissão de informações tanto no formato big-endian quanto no formato little-endian?
As linguagens XML e HTML possuem estrutura parecida, sendo essencialmente estruturada com a utilização de tags. O que as diferencia?
Por que a XML é dita extensível? O CORBA também é extensível? Justifique.
Uma definição XML é totalmente escrita com caracteres entre tags. É possível, assim, representar dados binários? Justifique?
Qual a diferença entre comunicação persistente e comunicação transiente?
Qual a diferença entre comunicação síncrona e comunicação assíncrona?
Como a técnica de chamada de procedimento remoto (RPC) pode ser utilizada na construção de sistemas distribuídos?
Por que é difícil a implementação de passagem de parâmetros por referência em uma chamada de procedimento remota (RPC)?
Qual a finalidade dos apêndices de cliente e de servidor (stubs) em um sistema de chamada de procedimento remoto (RPC)? Qual o impacto deles para a transparência?
Qual a importância de uma linguagem de definição de interface (IDL) para um sistema distribuído?
O que faz um compilador de uma linguagem de definição de interface?
O que diferencia a RPC da RPC assíncrona?
Como funciona a invocação a método remoto (RMI)?
A invocação a método remoto (RMI), por ser mais moderna que a chamada de procedimento remoto (RPC), estende alguns aspectos desta última. Cite uma diferença positiva da RMI em relação à RPC.
Na técnica de invocação a método remoto (RMI) um objeto pode ser chamado por outro objeto que se encontra em um processo diferente. Que informações o processo chamador precisa ter do objeto chamado para que possa ser realizada esta invocação remota?
Na invocação a método remoto (RMI), um objeto que recebe invocações remotas pode receber também invocações locais? Explique.
Qual a importância da interface de um objeto em um sistema de invocação a método remoto (RMI)?
Em um sistema baseado em invocação a método remoto (RMI), o que podemos afirmar sobre referências às variáveis locais na interface de um objeto?
A interface de Berkeley define soquetes (sockets) e funções para uma comunicação transiente orientada a mensagens. O que significa?
A interface de Berkeley fornece acesso à pilha de protocolos da internet. Ela permite ao programador acesso a qual camada?
A interface de troca de mensagens (MPI) estende a comunicação oferecida pela interface de Berkeley. Que novo tipo de comunicação ela oferece?
Um sistema de troca de mensagens pode ser baseado em um middleware orientado a mensagem (MOM). Como funciona o enfileiramento de mensagens? 
Em um sistema baseado em middleware orientado a mensagem (MOM) cliente

Continue navegando