.NET Remoting Um estudo ao suporte de invocac¸oes ˜ em objectos remotos na plataforma .NET Milton Moura
Ricardo Seabra
Faculdade de Ciencias e Tecnologia ˆ Universidade Nova de Lisboa Pos-Graduac ¸ ao ´ ˜ em Enga Informatica ´
Faculdade de Ciencias e Tecnologia ˆ Universidade Nova de Lisboa Licenciatura em Enga Informatica ´
[email protected]
[email protected]
RESUMO
infra-estruturas deste tipo, como os stubs, o processo de marshaling e a IDL [1]. A restante plataforma .NET ´e constitu´ıda por um ambiente controlado de execu¸c˜ ao de c´ odigo, designado por CLR (Common Language Runtime), um gestor de mem´ oria, respons´ avel pela recolha autom´ atica de referˆencias n˜ ao utilizadas, um sistema de tipos unificado (Common Type System) que permite a interoperabilidade entre objectos implementados em diferentes linguagens de programa¸c˜ ao, compiladas por uma ferramenta que implemente a CLS (Common Language Specification), e um conjunto de APIs, separados em m´ odulos l´ ogicos, que enriquece o modelo de objectos base fornecido [5].
Existe hoje em dia um n´ umero consider´ avel de tecnologias orientadas para a programa¸c˜ ao de sistemas de objectos distribu´ıdos, como s˜ ao exemplo disso o CORBA, o Java/RMI, o DCOM e, mais recentemente, o .NET Remoting. Qualquer uma delas oferece um agregado de servi¸cos e funcionalidades que diferem na sua abordagem e implementa¸c˜ ao, tornandoas mais ou menos complexas e apropriadas para determinados cen´ arios de utiliza¸c˜ ao. Este trabalho resulta de uma an´ alise ao suporte de invoca¸c˜ oes em objectos remotos na plataforma de desenvolvimento .NET, tendo como ambiente de execu¸c˜ ao a implementa¸c˜ ao multi-plataforma da especifica¸c˜ ao CLI denominada Mono, e pretende expor os v´ arios aspectos dos servi¸cos disponbilizados pelo componente .NET Remoting, bem como a sua arquitectura e funcionamento interno. Numa vertente pr´ actica, s˜ ao apresentados alguns exemplos de diferentes t´ecnicas normalmente utilizadas em ambientes de sistemas de objectos distribu´ıdos, com o objectivo de oferecer assim uma vis˜ ao comparativa deste suporte em rela¸c˜ ao a outros j´ a estudados.
1.
2.
.NET REMOTING
Integrado na especifica¸c˜ ao da plataforma Microsoft .NET, o componente .NET Remoting permite o desenvolvimento de aplica¸c˜ oes distribu´ıdas, onde os objectos participantes podem ser executados em m´ aquinas e processos diferentes e em dominios aplicacionais distintos. Na g´enese do .NET Remoting est´ a uma implementa¸c˜ ao abstracta de comunica¸c˜ ao entre processos que separa os objectos remotos e seus potenciais clientes do mecanismo de comunica¸c˜ ao entre si, tornando-se assim uma plataforma flex´ıvel e extens´ıvel, onde os protocolos de comunica¸c˜ ao e ´ formatos de serializa¸c˜ ao podem ser facilmente alterados. E tamb´em agn´ ostica ao modelo da aplica¸c˜ ao, possibilitando a interoperabilidade entre aplica¸c˜ oes Web, servi¸cos de sistema ou programas executados na consola. A plataforma disponibiliza ainda um conjunto de servi¸cos comuns em ambientes de middleware, como o suporte ` a activa¸c˜ ao de objectos remotos, gest˜ ao do seu ciclo de vida e seguran¸ca nos canais de mensagens.
˜ INTRODUC ¸ AO
As tecnologias de suporte aos sistemas distribu´ıdos de objectos permitem que componentes em execu¸c˜ ao numa determina m´ aquina sejam acedidos por aplica¸c˜ oes ou objectos em execu¸c˜ ao noutras m´ aquinas distintas. Tecnologias como o CORBA, o Java/RMI, o DCOM e o .NET Remoting s˜ ao exemplos de sistemas deste tipo e, apesar de estarem implementados de forma muito diferente e com funcionalidades distintas, mantˆem algumas semelhan¸cas: • Os objectos tˆem uma identidade u ´nica e podem ter um estado de execu¸c˜ ao.
2.1
• A utiliza¸c˜ ao de objectos remotos tem a mesma sem˜ antica dos objectos locais.
Meta-Modelo de Objectos e Definic¸a˜ o de Interfaces
O c´ odigo executado na plataforma .NET tem v´ arios n´ıveis de isolamento, sendo que num processo da CLR podem estar em execu¸c˜ ao v´ arios dom´ınios aplicacionais. Em qualquer dom´ınio aplicacional s˜ ao dadas as seguintes garantias:
• Est˜ ao associados a um modelo de componentes, onde os detalhes de implementa¸c˜ ao est˜ ao escondidos. • Tˆem modelos de tolerˆ ancia a falhas bem definidos.
1. Uma aplica¸c˜ ao pode ser parada de forma independente.
A implementa¸c˜ ao de suporte ` a invoca¸c˜ ao de objectos remotos no .NET Remoting ´e semelhante ` a do Java/RMI [7] em muitos aspectos, pois ambos tˆem como base a especifica¸c˜ ao de Birrel et al [2] para RPC’s (Remote Procedure Calls), que introduziu os conceitos b´ asicos utilizados nas
2. Uma aplica¸c˜ ao n˜ ao pode aceder directamente a c´ odigo e recursos de outra aplica¸c˜ ao. 3. Uma falha na aplica¸c˜ ao n˜ ao afecta as restantes aplica¸c˜ oes. 1
4. A configura¸c˜ ao da aplica¸c˜ ao determina o local de onde o c´ odigo ´e carregado e a sua vers˜ ao.
Os tipos de objectos remotos podem ser classificados de acordo com trˆes categorias: marshal-by-value, marshal-byreference ou context-bound. As instˆ ancias dos tipos marshalby-value podem ser enviadas entre dom´ınios aplicacionais atrav´es de um processo de serializa¸c˜ ao, que corresponde ` a codifica¸c˜ ao do estado actual de um objecto numa sequˆencia de bits. A recep¸c˜ ao de um objecto deste tipo resulta na cria¸c˜ ao de uma c´ opia no destino, com o mesmo estado do objecto original. Os objectos deste tipo s˜ ao caracterizados por um atributo especificado na sua defini¸c˜ ao, o atributo Serializable. No entanto, ´e poss´ıvel que um objecto definido com este atributo contenha propriedades que n˜ ao se destinem a ser transmitidas. Para tal, deve-se colocar o atributo NonSerializable no campo em causa. Os objectos do tipo marshal-by-reference s˜ ao utilizados quando se pretende manter uma u ´nica instˆ ancia desse tipo acess´ıvel num determinado dom´ınio aplicacional, sendo passada uma referˆencia dessa instˆ ancia aos seus clientes, em vez de uma c´ opia serializada. Assim, para que os objectos possam ser acedidos remotamente, estes tˆem de derivar do tipo MarshalByRefObject (ver Figura 2), de forma a suportar essa funcionalidade. As referˆencias envolvidas neste processo s˜ ao objectos do tipo ObjRef.
Um dom´ınio aplicacional pode ainda ser dividido em contextos, que asseguram uma s´erie de restri¸c˜ oes e semˆ antica de seguran¸ca no acesso aos objectos que neles se encontrem em execu¸c˜ ao. Por omiss˜ ao, todo o dom´ınio aplicacional cont´em pelo menos um contexto, onde s˜ ao criados todos os objectos, excepto aqueles que necessitam de um novo contexto especializado.
[Serializable] public abstract class MarshalByRefObject { protected MarshalByRefObject () { }
Figura 1: N´ıveis de isolamento da CLR.
2.1.1
internal Identity GetObjectIdentity ( MarshalByRefObject obj, out bool IsClient );
Objectos
O .NET Remoting possbilita a invoca¸c˜ ao de m´etodos so´ inbre objectos remotos, em execu¸c˜ ao num CLR host. E diferente ao sistema a linguagem em que est˜ ao implementados os objectos servidores e objectos clientes, podendo esta ser distinta. O sistema unificado de tipos da plataforma gere a representa¸c˜ ao interna dos objectos e garante assim a sua interoperabilidade. A invoca¸c˜ ao remota de m´etodos depende da obten¸c˜ ao de uma referˆencia para o objecto remoto, referˆencia esta que cont´em uma s´erie de meta-dados necess´ arios para que o cliente efectue a invoca¸c˜ ao de forma transparente, utilizando uma semˆ antica de acesso idˆentica ` a dos objectos locais. A obten¸c˜ ao dessa referˆencia ´e levado a cabo atrav´es de um canal de comunica¸c˜ oes estabelecido com o servidor, designado por um URI (Universal Resource Identifier ) de acesso u ´nico. Ao iniciar, ´e da responsabilidade do servidor registar ambos estas propriedades na plataforma.
2.1.2
[NonSerialized] internal ServerIdentity ObjectIdentity { get; set; } public virtual ObjRef CreateObjRef (Type type); public virtual object GetLifetimeService (); public virtual object InitializeLifetimeService (); } Figura 2: Excerto da classe MarshalByRefObject Por u ´ltimo, os tipos context-bound constituem uma especializa¸c˜ ao do objecto remoto t´ıpico, passado por referˆencia, que neste caso est´ a restrito ao contexto de execu¸c˜ ao em que ´e instanciado. Isto significa que o seu acesso, inclusive a partir do mesmo dom´ınio aplicacional, envolve sempre o envio de uma referˆencia remota para os objectos clientes, em vez da invoca¸c˜ ao local normal que seria de esperar em situa¸c˜ oes deste tipo. Essa funcionalidade ´e adquirida derivando do tipo ContextBoundObject. Os restantes tipos n˜ ao-remotos definidos para a plataforma .NET s˜ ao suportados pela API de Remoting de forma transparente, possibilitando a utiliza¸c˜ ao de qualquer classe, interface, enumera¸c˜ ao e objecto, sem quaisquer limita¸c˜ oes. Partindo do princ´ıpio que tanto os clientes como os objectos servidor est˜ ao contidos em plataformas de execu¸c˜ ao idˆenticas, isto ´e, em CLRs baseadas numa mesma vers˜ ao de implementa¸c˜ ao, a interoperabilidade a n´ıvel de tipos de dados est´ a solucionada ` a partida.
Tipos
Com o objectivo de possibilitar a interac¸c˜ ao entre objectos residentes em diferentes n´ıveis de isolamento da plataforma, os tipos de objectos objectos podem ser classificados de remotos ou n˜ ao-remotos. Um tipo ´e considerado remoto se: 1. As suas instˆ ancias podem atravessar os n´ıveis de isolamento da plataforma. 2. Outros objectos podem aceder a instˆ ancias do tipo, atravessando os n´ıveis de isolamento da plataforma. Qualquer tipo de objecto que n˜ ao satisfa¸ca estas propriedades, ´e n˜ ao-remoto. 2
2.1.3
delegate string MyDelegate(int myValue); string DoSomething(int myValue);
Atributos
Um tipo de objecto remoto pode definir atributos, designados por propriedades na plataforma .NET, e especificar se estes s˜ ao s´ o de leitura ou de leitura e escrita. No entanto, a sua implementa¸c˜ ao interna, forma de acesso e representa¸c˜ ao s˜ ao em tudo idˆenticas aos dos m´etodos.
MyDelegate md = new MyDelegate(DoSomething); // invoca¸ c~ ao ass´ ıncrona IAsyncResult ar = md.BeginInvoke( someValue, null, null);
interface IRemoteObject { int MyRemoteMethod(); // propriedade s´ o de leitura double MyFloatProperty { get; } // propriedade de leitura-escrita int MyIntProperty { get; set; } }
// obten¸ c~ ao do resultado string result = md.EndInvoke(ar); Figura 4: Exemplo de invoca¸ c˜ ao ass´ıncrona ´ tamb´em suportado um modo de inretorno da fun¸c˜ ao. E voca¸c˜ ao ass´ıncrona num s´ o sentido, ou seja, os m´etodos n˜ ao podem possuir retorno ou parˆ ametros de sa´ıda. Apesar de existir uma API de reflex˜ ao na especifica¸c˜ ao da CLI (System.Reflection), esta n˜ ao est´ a integrada com o Remoting de forma a possibilitar a invoca¸c˜ ao dinˆ amica de opera¸c˜ oes. Est´ a portanto limitada ` a invoca¸c˜ ao est´ atica e dependente do acesso ` a defini¸c˜ ao dos tipos dos objectos num assembly local ou registado na GAC (Global Assembly Cache).
Figura 3: Exemplo de defini¸ c˜ ao de propriedades
2.1.4
Operac¸o˜ es
Designados por m´etodos, as opera¸c˜ oes em Remoting podem ser invocadas desde que declaradas como p´ ublicas na implementa¸c˜ ao do tipo de objecto remoto. Caso o objecto remoto seja uma implementa¸c˜ ao de um ou mais interfaces, ent˜ ao todos os m´etodos implementados, necess´ arios para satisfazer o contrato, s˜ ao p´ ublicos. A semˆ antica de invoca¸c˜ ao das opera¸c˜ oes remotas ´e muito semelhante ` a dos m´etodos locais, uma vez que os parˆ ametros podem ser passados por referˆencia ou por valor. A passagem de um parˆ ametro por referˆencia significa que ´e passado um apontador com a informa¸c˜ ao necess´ aria para que a opera¸c˜ ao o manipule, tal como a sua localiza¸c˜ ao e outros dados necess´ arios. A passagem de objectos por valor resulta na cria¸c˜ ao de uma c´ opia no contexto de execu¸c˜ ao do m´etodo invocado, idˆentica ` a do objecto submetido. No entanto, quando est˜ ao envolvidos objectos remotos, a sua passagem como parˆ ametro de um m´etodo remoto depende do seu tipo, mais precisamente, se este ´e marshal-byreference ou marshal-by-value.
2.1.5
2.1.6
Tratamento de erros
O tratamento de erros, ` a semelhan¸ca do que acontece na restante plataforma, ´e efectuada atrav´es da propaga¸c˜ ao de excep¸c˜ oes, objectos do tipo Exception que dever˜ ao ser definidos como serializ´ aveis, de forma a poderem ser transformadas e enviados pelos canais de comunica¸c˜ ao definidos entre os objectos remotos e clientes envolvidos. Em particular, os erros com origem na infra-estrutura de Remoting, lan¸cam apenas um tipo de excep¸c˜ ao: o RemotingException. Uma excep¸c˜ ao deste tipo pode ser levantada por in´ umeras raz˜ oes, entre as quais: ´ instanciado um tipo de objecto remoto que n˜ • E ao deriva de MarshalByRefObject. • Especifica¸c˜ ao inv´ alida do ponto de acesso de um tipo de objecto remoto, isto ´e, o URI est´ a mal formado.
Invocac¸o˜ es
A semˆ antica de invoca¸c˜ oes nesta plataforma ´e do tipo atmost-once, o que significa que a recep¸c˜ ao de uma excep¸c˜ ao resultante de uma invoca¸c˜ ao remota indica que o m´etodo alvo poder´ a n˜ ao ter sido executado. Por outro lado, a inexistˆencia de erros constitui uma garantia de que a opera¸c˜ ao foi executada com sucesso no objecto remoto. Podem ser efectuados trˆes tipos diferentes de invoca¸c˜ oes sobre objectos remotos: s´ıncronas, ass´ıncronas, e ass´ıncronas num s´ o sentido (oneway). O modo s´ıncrono consiste no bloqueio do cliente, ap´ os a invoca¸c˜ ao, at´e que alguma resposta ou excep¸c˜ ao seja enviada pelo servidor ou pela plataforma. Para fazer face ao potencial fraco desempenho das chamadas s´ıncronas, o .NET Remoting suporta um mecanismo de invoca¸c˜ oes ass´ıncronas, assente na utiliza¸c˜ ao de delegates. Os delegates fornecem um mecanismo de callback com verifica¸c˜ ao de tipos, permitindo a invoca¸c˜ ao ass´ıncrona de opera¸c˜ oes locais ou remotas (ver Figura 4). Assim, a invoca¸c˜ ao do m´etodo ´e feita em dois passos: em primeiro lugar despoleta-se a invoca¸c˜ ao da opera¸c˜ ao remota a partir do m´etodo BeginInvoke(). Este m´etodo retorna um objecto IAsyncResult que ir´ a permitir obter o valor de
• Protocolos de comunica¸c˜ ao diferentes entre os clientes e os objectos servidor. • A invoca¸c˜ ao de opera¸c˜ oes sobre objectos remotos que n˜ ao est˜ ao em execu¸c˜ ao, nem foram activados.
2.1.7
Sub-tipos e heranc¸a m´ultipla
A plataforma .NET n˜ ao suporta heran¸ca de m´ ultiplas implementa¸c˜ oes, mas suporta a heran¸ca de m´ ultiplos interfaces. Assim, um tipo de objecto pode extender uma implementa¸c˜ ao e implementar m´ ultiplos interfaces. Esta caracter´ıstica permite que os objectos remotos sejam sub-tipos da implementa¸c˜ ao MarshalByRefObject e que, ao mesmo tempo, implementem interfaces n˜ ao remotos.
2.1.8
Polimorfismo
O suporte ao polimorfismo est´ a estaticamente restricto pela heran¸ca de m´ ultiplos interfaces. A qualquer objecto do sistema est´ a associado um tipo est´ atico, sendo apenas poss´ıvel atribu´ır a este instˆ ancias de objectos cujo tipo est´ atico 3
´ poss´ıvel ent˜ seja um super-tipo do objecto em quest˜ ao. E ao redefinir determinadas opera¸c˜ oes herdadas pelos sub-tipos e determinar a execu¸c˜ ao da opera¸c˜ ao correcta atrav´es de mecanismos de late-binding. Esta garantia de consistˆencia da representa¸c˜ ao dos tipos distribu´ıdos e a coerˆencia do modelo de objectos permite instituir uma no¸c˜ ao de polimorfismo distribu´ıdo, abrindo portas ao suporte de migra¸c˜ ao de c´ odigo entre dom´ınios aplicacionais e contextos de execu¸c˜ ao distintos.
2.2
localmente no objecto remoto e o seu resultado encapsulado numa mensagem que percorre o trajecto inverso.
Arquitectura
Como a maioria dos sistemas de objectos distribu´ıdos, o .NET Remoting recorre ao modelo tradicional de suporte ` a invoca¸c˜ ao de opera¸c˜ oes em objectos remotos, que consiste na implementa¸c˜ ao dessas opera¸c˜ oes numa classe, por sua vez instanciada num processo anfitri˜ ao, em execu¸c˜ ao num local conhecido e acess´ıvel aos clientes. Como o contexto de execu¸c˜ ao do objecto remoto est´ a isolado em rela¸c˜ ao ao do cliente, a invoca¸c˜ ao dos m´etodos remotos tem de ser efectuada atrav´es de um stub ou proxy, uma c´ opia local do objecto remoto que adere a ` sua defini¸c˜ ao de tipo. A invoca¸c˜ ao destes m´etodos expostos pelo proxy resulta no envio de mensagens serializadas atrav´es da rede. As mensagens s˜ ao transferidas pelo canal de comunica¸c˜ ao estabelecido entre o cliente e o servidor, sendo efectuado o processo inverso de serializa¸c˜ ao ap´ os a sua recep¸ca ˜o no servidor e submetido (dispatched ) o m´etodo para invoca¸c˜ ao no objecto remoto. O processo de envio do resultado da invoca¸c˜ ao ´e an´ alogo, mas em sentido contr´ ario.
Figura 6: Entidades envolvidos na invoca¸ c˜ ao de um m´ etodo remoto.
2.2.1
Referˆencias Remotas
As referˆencias para os objectos remotos, envolvidos no processo descrito anteriormente, s˜ ao do tipo ObjRef e contˆem toda a informa¸c˜ ao necess´ aria para a cria¸c˜ ao dos proxys j´ a mencionados. A referˆencia cont´em, entre outros dados, o URI que constitui o ponto de acesso conhecido para o objecto em quest˜ ao, uma s´erie de meta-dados que descrevem o tipo do objecto remoto, tal como o nome do assembly que cont´em a sua implementa¸c˜ ao, a sua vers˜ ao e chaves p´ ublicas, entre outros. Dados acerca de todos os tipos da hierarquia de deriva¸c˜ ao tamb´em s˜ ao agrupados nesta referˆencia e serializados de forma a serem enviados ao cliente. Ainda ´e inclu´ıda informa¸c˜ ao relativa ao contexto de execu¸c˜ ao, dom´ınio aplicacional e processo que cont´em o objecto associado ` a referˆencia, bem como a identifica¸c˜ ao do tipo de canal, endere¸co e porta que dever˜ ao ser utilizados nos pedidos de invoca¸c˜ ao remota.
Figura 5: Arquitectura das plataformas de suporte a sistemas de objectos distribu´ıdos. Em particular, na infra-estrutura de Remoting, assim que um cliente activa um objecto remoto, a plataforma cria uma instˆ ancia local da classe TransparentProxy, que cont´em uma lista de todas classes e m´etodos dos interfaces do objecto remoto. Assim que esta classe ´e criada, todas as invoca¸c˜ oes sobre ela s˜ ao interceptados pelo runtime, de forma a determinar a sua validade e a existˆencia de uma instˆ ancia do objecto alvo no mesmo dom´ınio aplicacional em que o proxy est´ a em execu¸c˜ ao. Se existir, ent˜ ao ´e feito um encaminhamento simples para o m´etodo invocado no objecto local. Caso contr´ ario, ´e criado um objecto do tipo IMessage, onde s˜ ao colocados os parˆ ametros submetidos ao m´etodo remoto (caso existam), e encaminhada a mensagem para um objecto RealProxy, atrav´es do m´etodo Invoke(). Esta classe ´e respons´ avel pelo encaminhamento das mensagens para o objecto remoto, atrav´es de canais registados no servidor. Uma vez recebida a mensagem de invoca¸c˜ ao no dom´ınio aplicacional ou contexto de destino, o m´etodo ´e invocado
2.2.2
Mensagens
Na base do suporte a invoca¸c˜ oes sobre objectos remotos est˜ ao as mensagens, um tipo de objecto que abstrai o processo de invoca¸c˜ ao de m´etodos de uma forma orientada a objectos. Assim, uma mensagem pode encapsular a invoca¸c˜ ao de m´etodos, argumentos de entrada e valores de retorno, invoca¸c˜ oes a construtores de objectos, lan¸camento de excep¸c˜ oes, entre outros. Os objectos de mensagens implementam o tipo IMessage e s˜ ao serializ´ aveis.
2.2.3
Canais
As mensagens s˜ ao transmitidas entre os objectos intervenientes atrav´es de canais de comunica¸c˜ ao estabelecidos na altura de activa¸c˜ ao dos objectos remotos. Estes objectos s˜ ao extremamente extens´ıveis e permitem a constru¸c˜ ao de mecanismos de transporte suportados por uma variedade de 4
protocolos e formatos na transmiss˜ ao dos dados. No entanto, a plataforma disponibiliza apenas dois canais de transporte: o HttpChannel e o TcpChannel. O HttpChannel, por defeito, recorre ao SOAP (Simple Object Access Protocol ) para codificar as mensagens. O SOAP ´e um protocolo baseado em XML, desenhado para permitir a invoca¸c˜ ao de procedimentos remotos sobre HTTP, de forma a superar as restri¸c˜ oes impostas pelas firewalls em redes de larga escala. Em ambientes mais controlados, o TcpChannel verifica-se uma alternativa mais eficaz, uma vez que, por defeito, utiliza um formato bin´ ario, minimizando assim o tamanho das mensagens transmitidas e aumentando o desempenho da troca de mensagens entre objectos. Estes objectos implementam o interface IChannel e, de modo a suportar tanto o envio como a recep¸c˜ ao de dados, tamb´em implementam os tipos IChannelReceiver e IChannelSender. Os canais tˆem a particularidade de serem constitu´ıdos por uma s´erie de objectos logicamente encadeados, conhecidos por sinks, que aceitam mensagens, isto ´e, objectos do tipo IMessage, de um elemento anterior, efectuam alguma opera¸c˜ ao sobre estas e submetem-nas ao pr´ oximo elemento da cadeia de sinks.
mensagens atrav´es do canal. Entre outros, poderia ser desenvolvido um sink para a encripta¸c˜ ao de mensagens, outro que guardasse um log de todas as mensagens trocadas entre os objectos, ou ainda outro que exigisse algum tipo de autentica¸c˜ ao adicional por parte dos clientes envolvidos [4]. O desenvolvimento de novos formatters passa pela implementa¸c˜ ao do tipo ISerializable, que cont´em apenas o m´etodo GetObjectData(). Este m´etodo ´e chamado quando ´e necess´ ario serializar o objecto. Quando est˜ ao envolvidos tipos n˜ ao suportados por este m´etodo (por exemplo, referˆencias), a plataforma recorre a surrogates e surrogate selectors.
2.2.4
Activac¸a˜ o
A plataforma suporta a activa¸c˜ ao de objectos remotos a partir dos cliente ou do pr´ oprio servidor. A activa¸c˜ ao por parte do servidor ´e normalmente utilizada quando os objectos envolvidos n˜ ao tˆem necessidade de manter o seu estado entre diferentes opera¸c˜ oes, enquanto que, por outro lado, a activa¸c˜ ao a partir do cliente resulta numa instancia¸c˜ ao do objecto remoto a pedido do cliente, sendo a sua gest˜ ao do tempo de vida feita atrav´es de um sistema de leases. Assim, os objectos activados no servidor s˜ ao geridos por este, sendo instanciados apenas quando ocorre a primeira invoca¸c˜ ao por parte de um cliente. Este tipo de objectos apenas suporta construtores sem parˆ ametros e tˆem a sua localiza¸c˜ ao bem definida e conhecida, uma vez que est˜ ao associados a um URI. Podem ser de dois tipos distintos: Singleton ou SingleCall. Os objectos do tipo Singleton baseam-se no padr˜ ao de desenho com o mesmo nome e portanto dizem respeito a tipos de objectos que s˜ ao instanciados uma u ´nica vez e com um u ´nico ponto global de acesso durante o seu per´ıodo de execu¸c˜ ao [3]. Tal como os restantes tipos de objectos remotos, estes tamb´em tˆem um tempo de vida pr´e-determinado, o que significa que os seus clientes n˜ ao obter˜ ao necessariamente sempre uma referˆencia para a mesma instˆ ancia da classe remota. Este aspecto tem implica¸c˜ oes na gest˜ ao do estado destes objectos e pode ser contornado, for¸cando a manuten¸c˜ ao do objecto em mem´ oria, enquanto o dom´ınio aplicacional do servidor estiver em execu¸c˜ ao, atrav´es de uma lease nula. Assim, ´e poss´ıvel que este objecto mantenha um determinado estado entre invoca¸c˜ oes e que este seja modificado ou obtido por diferentes clientes. No entanto, este tipo de interac¸c˜ ao com objectos Singleton deve ser efectuada com alguma precau¸c˜ ao, uma vez que o seu acesso n˜ ao ´e sincronizado, podendo servir dois clientes concorrentes em threads de execu¸c˜ ao diferentes. Os tipos remotos SingleCall tˆem sempre uma instˆ ancia por pedido, de modo que cada invoca¸c˜ ao por parte de um cliente ´e servida por uma instˆ ancia diferente, com um estado distinto. Os objectos activados pelos clientes s˜ ao instanciados a partir do momento em que este cria um novo objecto do tipo remoto pretendido, com o operador new ou com o m´etodo Activator.CreateInstance(). Neste cen´ ario, o cliente pode participar na gest˜ ao da vida do objecto remoto, utilizando as j´ a mencionadas leases. Tamb´em possibilita a instancia¸c˜ ao parametrizada bem como a manuten¸c˜ ao do estado do objecto por cliente, uma vez que cada cliente tem a sua instˆ ancia distinta do objecto remoto em execu¸c˜ ao no servidor.
Figura 7: Transforma¸ c˜ oes de uma mensagem atrav´ es de um canal e da sua cadeia de sinks. Um dos elementos mais importantes, e normalmente o primeiro nesta cadeia de objectos, ´e o formatter sink, respons´ avel pela serializa¸c˜ ao da mensagem propriamente dita, preparando-a assim para ser transmitida pelo canal. Os elementos interm´edios podem efectuar processamento adicional sobre esta, sendo que o u ´ltimo elemento da cadeia fica ent˜ ao encarregado de transportar a mensagem pelo fio, de acordo com um protocolo de transporte espec´ıfico. Nos canais apresentandos anteriormente, cada qual tem o seu formatter apropriado. O HttpChannel utiliza um objecto do tipo SoapFormatter, enquanto que o TcpChannel utiliza um BinaryFormatter. Como j´ a foi mencionado, todos estes componentes podem ser extendidos. Em particular, podem ser introduzidos novos elementos na cadeia de sinks, substitu´ıdos ou removidos outros, de forma a manipular o processamento das 5
2.3
Heterogeneidade
2.5
A plataforma em estudo resolve de forma elegante e eficaz os problemas associados ` a heterogeneidade, normalmente discutidos nos sistemas de objectos distribu´ıdos.
2.3.1
Nesta plataforma, a problem´ atica relativa ` a gest˜ ao do ciclo de vida dos objectos ´e solucionada com recurso ` a utiliza¸c˜ ao de leases e sponsorships que, uma vez associadas aos objectos remotos, evitam que estes sejam recolhidos pelo mecanismo local de recolha de lixo. A excep¸c˜ ao a este cen´ ario reside nos objectos single-call activados no servidor, que s˜ ao desactivados imediatamente ap´ os uma invoca¸c˜ ao sobre as suas opera¸c˜ oes.
Linguagens de Programac¸a˜ o
A existˆencia de um sistema de tipos comum, que garante a interoperabilidade e integra¸c˜ ao dos tipos, atrav´es da imposi¸c˜ ao de regras e especifica¸c˜ ao de um modelo de objectos comum, resolve o problema da utiliza¸c˜ ao de v´ arias linguagens de programa¸c˜ ao no processo de desenvolvimento. Todo o c´ odigo produzido por uma linguagem que esteja especificada de acordo com o Common Type System ´e traduzido para uma linguagem interm´edia comum, que mais tarde ´e interpretada pelo runtime e transformada em c´ odigo nativo.
2.3.2
2.5.1
Representac¸a˜ o dos dados
Uma vez que o c´ odigo nativo ´e executado em runtimes devidamente condicionados e baseados na mesma implementa¸c˜ ao, a heterogeneidade na representa¸c˜ ao dos dados n˜ ao ´e um problema, desde que o ambiente de execu¸c˜ ao seja comum, isto ´e, tenha como base a mesma vers˜ ao de uma determinada implementa¸c˜ ao da CLI. A utiliza¸c˜ ao de diferentes implementa¸c˜ oes e vers˜ oes de uma ou mais CLI’s n˜ ao garante a representa¸c˜ ao homog´enea dos dados, uma vez que a estrutura interna dos tipos pode ter sido alterada, tornando-as efectivamente incompat´ıveis.
2.4
Gest˜ao do Ciclo de Vida
Localizac¸a˜ o
A designa¸c˜ ao de servi¸cos remotos na plataforma consiste na atribui¸c˜ ao de URIs bem conhecidos aos objectos e s˜ ao definidos na fase em que estes s˜ ao registados na plataforma. O registo de objectos ´e normalmente realizado pela aplica¸c˜ ao que os instancia, registando os canais de comunica¸c˜ ao atrav´es de opera¸c˜ oes disponibilizadas pela classe ChannelServices e os objectos remotos atrav´es da classe RemotingConfiguration. O registo de um objecto remoto s´ o ´e poss´ıvel mediante a seguinte informa¸ca ˜o: 1. o nome do tipo do objecto remoto. 2. o URI que o designa. 3. o tipo de activa¸c˜ ao. No caso dos objectos activados pelo servidor, esse URI ´e fixo e conhecido, enquanto que nos objectos activados pelos clientes, esse URI ´e gerado e relativo a uma instˆ ancia particular do tipo de objecto no servidor. // registo de um canal de comunica¸ c~ ao TcpChannel channel = new TcpChannel(4321); ChannelServices.RegisterChannel(channel);
Leases e Sponsors
Tal como os restantes sistemas de objectos distribu´ıdos, em .NET Remoting a gest˜ ao de ciclo de vida est´ a associada ao mecanismo de recolha de lixo, que mant´em informa¸c˜ ao acerca dos objectos em utiliza¸c˜ ao pelos clientes. Quando um objecto deixa de ser referenciado pelos clientes, ´e recolhido e eventualmente destru´ıdo, sendo libertada a mem´ oria anteriormente atribu´ıda. Este processo ´e eficaz num cen´ ario onde as aplica¸c˜ oes partilham o mesmo processo de execu¸c˜ ao (a mesma CLR). Num cen´ ario distribu´ıdo, a situa¸c˜ ao ´e diferente, uma vez que um objecto pode n˜ ao ter clientes locais, mas sim clientes que est˜ ao em execu¸c˜ ao em processos e m´ aquinas diferentes, onde a recolha prematura de um objecto resultaria na invalida¸c˜ ao da referˆencia remota possu´ıda pelos clientes. A solu¸c˜ ao implementada na plataforma .NET envolve a utiliza¸c˜ ao de leases e funciona da seguinte forma: o acesso a um objecto no servidor por parte de um cliente resulta na associa¸c˜ ao deste a um objecto lease, que mantˆem, entre outras propriedades, um per´ıodo de tempo durante o qual o objecto servidor n˜ ao dever´ a ser recolhido. O lease manager, respons´ avel pela gest˜ ao das associa¸c˜ oes entre objectos e leases, d´ a in´ıcio ` a contagem decrescente do tempo de lease a partir do momento em que a primeira referˆencia ´e enviada para fora do seu dom´ınio de execu¸c˜ ao. Esta entidade tamb´em mant´em uma referˆencia para o objecto servidor, evitando assim a sua recolha para destrui¸c˜ ao. Uma vez expirada a lease de um objecto, a CLR assume que n˜ ao existem clientes a utilizar referˆencias remotas e descarta tamb´em a sua referˆencia local [6]. No entanto, n˜ ao s˜ ao dadas garantias de que n˜ ao existam ainda clientes que possuam referˆencias para os objec´ ent˜ tos remotos. E ao necess´ ario providenciar uma forma de estes poderem extender as leases. Aqueles clientes que precisam de ser contactados quando o tempo de vida de um objecto remoto termina devem recorrer a um objecto sponsor, registando-o na lease respectiva. Assim, o gestor de leases percorre a lista de sponsors associada ` a lease do objecto em quest˜ ao e identifica se h´ a ou n˜ ao necessidade de extender o seu tempo de vida.
2.5.2
Propriedades das Leases
Uma lease ´e instanciada com valores atribu´ıdos por omiss˜ ao `s suas propriedades (ver Figura 9), mas que podem ser ala terados antes de serem registados os objectos no servidor, quer programaticamente, quer atrav´es dos ficheiros de configura¸c˜ ao da aplica¸c˜ ao. A propriedade RenewOnCallTime tem um valor de tempo adicional que ´e automaticamente acrescentado ao tempo de vida do objecto caso sejam invocados m´etodos sobre este, perto da expira¸c˜ ao da sua lease. Esta renova¸c˜ ao do tempo de lease s´ o ´e efectuada caso o restante tempo de vida do objecto seja inferior ao valor atribu´ıdo ` a propriedade anteri-
// registo do tipo de objecto remoto RemotingConfiguration.RegisterWellKnownServiceType( typeof(MyRemoteObject), "MyRemoteObjectUri", WellKnownObjectMode.Singleton ); Figura 8: Registo t´ıpico de um objecto remoto.
6
public sealed class LifetimeServices { TimeSpan LeaseManagerPollTime { get; set; } TimeSpan InitialLeaseTime { get; set; } TimeSpan RenewOnCallTime { get; set; } TimeSpan SponsorshipTimeout {get; set; }
tratamento e persistˆencia de estruturas de dados relacionais, designado por ADO.NET. Esta API em conjunto com o processo de serializa¸c˜ ao de objectos j´ a abordado, poderia estar na base da implementa¸c˜ ao de um servi¸co de persistˆencia orientado para o armazenamento dos objectos remotos, particularmente u ´til na salvaguarda a longo-prazo do estado de execu¸c˜ ao de servidores.
static LifetimeServices() { LeaseManagerPollTime = TimeSpan.FromSeconds(10); LeaseTime = TimeSpan.FromMinutes(5); RenewOnCallTime = TimeSpan.FromMinutes(2); SponsorshipTimeout = TimeSpan.FromMinutes(2); }
2.7
A interoperabilidade da plataforma .NET Remoting em rela¸c˜ ao a outros sistemas de objectos distribu´ıdos assenta sobretudo no protocolo SOAP e no mecanismo de pedidos de invoca¸c˜ oes remotas facultado, expressos sob a forma de mensagens SOAP. Este protocolo especifica um formato XML normalizado, que permite a inclus˜ ao de defini¸c˜ oes de tipos e dados estruturados, independente da plataforma e linguagem de programa¸c˜ ao utilizadas. Esta possibilidade de oferecer servi¸cos web, baseados em XML, a clientes potencialmente desenvolvidos sobre outras plataformas e arquitecturas, garante que as mensagens podem ser trocadas e entendidas entre sistemas diferentes, escondendo assim os detalhes de implementa¸c˜ ao dos servi¸cos remotos.
} Figura 9: Classe LifetimeServices ormente mencionada, evitando assim que um objecto remoto que seja bastante solicitado pelos seus clientes aumente progressivamente o seu tempo de vida. A propriedade LeaseManagerPollTime indica a dura¸c˜ ao do intervalo de tempo que dever´ a decorrer entre a verifica¸c˜ ao dos tempos das leases, que por omiss˜ ao ´e de 10 segundos, enquanto que a propriedade SponsorshipTimeout especifica o tempo que o servidor dever´ a esperar por respostas dos clientes remotos quando inquire estes acerca do estado da sua sponsorship. Esta propriedade ´e importante pois ´e a partir deste valor que s˜ ao toleradas falhas de comunica¸c˜ ao com os clientes, sendo estes removidos da lista de sponsors da lease caso n˜ ao respondam dentro do intervalo de tempo estabelecido. Um objecto remoto pode tamb´em alterar as propriedades do seu ciclo de vida ap´ os a sua instancia¸c˜ ao, fornecendo uma implementa¸c˜ ao para o m´etodo InitializeLifetimeService e devolvendo um objecto do tipo ILease.
2.5.3
2.8
Configurabilidade
De forma a introduzir alguma flexibilidade na configura¸c˜ ao dos servi¸cos oferecidos pelos objectos remotos, a plataforma suporta o carregamento de determinadas propriedades a partir de ficheiros, sem ser necess´ ario recompilar o c´ odigo. ´ poss´ıvel ent˜ E ao especificar num ficheiro de configura¸c˜ ao a porta e o tipo de canal utilizado no estabelecimento de liga¸c˜ oes ao objecto remoto, o seu modelo de activa¸c˜ ao, o URI de acesso, entre outras propriedades importantes (ver Figura 10).
<system.runtime.remoting> <service> <wellknown mode="Singleton" type="MyServerImpl, MyServerLib" objectUri="MyURI" />
Sponsors
Como foi referido anteriomente, um sponsor ´e utilizado para possibilitar um pedido de renova¸c˜ ao do lease por parte do cliente, quando este est´ a prestes a expirar. Este processo de renova¸c˜ ao envolve a invoca¸c˜ ao do m´etodo Renewal no objecto sponsor, pelo gestor de leases. Uma vez que os objectos sponsor est˜ ao associados aos clientes e tˆem de ser registados no servidor, ter˜ ao de derivar da classe MarshalByRefObject e ser enviados por referˆencia, ou ent˜ ao marcados como Serializable e enviados por valor. Na primeira hip´ otese, o cliente dever´ a garantir a manuten¸c˜ ao de uma referˆencia para este objecto remoto e remover o seu registo quando j´ a n˜ ao for necess´ ario, ganhando nesta situa¸c˜ ao a vantagem de poder controlar as suas decis˜ oes com base em eventos ou propriedades associadas ao cliente. Por outro lado, se o objecto sponsor for enviado por valor, ´e criada uma c´ opia no servidor que, apesar de ser transferida de forma mais eficiente , apenas poder´ a basear as suas decis˜ oes nas propriedades do servidor.
2.6
Interoperabilidade
Figura 10: Exemplo de um ficheiro de configura¸ c˜ ao
2.9
Ambientes de Execuc¸a˜ o
Uma vez que os objectos remotos s´ o podem ser activados ap´ os efectuado o seu registo e o dos seus canais de comunica¸c˜ ao, esse processo dever´ a ser efectuado por uma aplica¸c˜ ao designada para esse fim. Essa aplica¸c˜ ao dever´ a estar em execu¸c˜ ao durante todo o ciclo de vida dos objectos registados. Em ambientes Microsoft Windows, essa aplica¸c˜ ao pode ser substitu´ıda por um servi¸co gen´erico desenvolvido com esse objectivo, ou ent˜ ao associada a um de dois servi¸cos
Persistˆencia
O suporte ao armazenamento de tipos de objectos num reposit´ orio de dados persistente n˜ ao constitui um servi¸co intrinsecamente ligado ao .NET Remoting, mas est´ a presente na plataforma .NET como um componente gen´erico para o 7
j´ a existentes: o IIS (Internet Information Services) ou aos servi¸cos COM+.
2.9.1
a interoperabilidade entre objectos desenvolvidos em diferentes linguagens, possibilitando a execu¸c˜ ao e comunica¸c˜ ao entre estes num ambiente CLI, onde o tratamento de erros estabelecido segue um modelo at-most-once. A utiliza¸c˜ ao de proxys como mecanismo de atingir um modelo de transparˆencia de acesso ´e comum a todos os sistemas referidos, sendo de real¸car que em Remoting, a cria¸c˜ ao e manipula¸c˜ ao dos objectos deste tipo ´e completamente invis´ıvel para o utilizador ou programador. O mecanismo de leases constitui o modelo de recolha de objectos para os quais j´ a n˜ ao existem referˆencias e est˜ ao tamb´em implementadas variadas formas de suporte ` a activa¸c˜ ao dinˆ amica dos objectos servidores. Em suma, a infra-estrutura de Remoting tem bastantas semelhan¸cas com a do Java/RMI, mas oferece de raiz, em determinados aspectos, mais funcionalidades associadas ao tratamento dos objectos remotos, e na configura¸c˜ ao e extens˜ ao dos canais de comunica¸c˜ ao. A interoperabilidade com outras plataformas atrav´es de protocolos como o SOAP e HTTP evidencia tamb´em uma abertura para a integra¸c˜ ao entre sistemas com diferentes implementa¸c˜ oes.
Integrac¸a˜ o no IIS
O IIS ´e um servidor web e normalmente est´ a sempre em execu¸c˜ ao num ambiente Windows. Como tal, presta-se a ser um bom anfitri˜ ao aos componentes remotos que se querem disponibilizar, apesar de estar limitado ` a utiliza¸c˜ ao de canais HttpChannel. Por outro lado, possibilita uma configura¸c˜ ao r´ apida das restri¸c˜ oes de seguran¸ca impostas aos componentes e a altera¸c˜ ao da sua configura¸c˜ ao sem ser necess´ ario reiniciar o servi¸co.
2.9.2
Integrac¸a˜ o nos servic¸os COM+
Outra op¸c˜ ao passa por tirar partido das funcionalidades oferecidas pelo ambiente COM+, tais como o suporte a transac¸c˜ oes distribu´ıdas, seguran¸ca baseada em roles, e pooling de objectos. Um componente remoto pode participar do contexto de execu¸c˜ ao dos servi¸cos COM+ derivando da classe ServicedComponent. Esta classe, e o espa¸co de nomes System.EnterpriseServices, possibilita a utiliza¸c˜ ao de atributos particulares ao COM+ num objecto em execu¸c˜ ao na CLR e a todos os benef´ıcios que da´ı resultam.
3.
5.
EXEMPLOS
Procedeu-se ao desenvolvimento de um conjunto de exemplos simples, demonstrativos das funcionalidades disponibilizadas pelo infra-estrutura de Remoting, sobre uma implementa¸c˜ ao da CLI open source e compat´ıvel com sistemas UNIX, designada por Mono e dispon´ıvel em http://www.monoproject.com/. Esta distribui¸c˜ ao implementa toda a funcionalidade da vers˜ ao 1.1 da plataforma .NET dispon´ıvel para sistemas operativos Microsoft Windows e ainda extende a distribui¸c˜ ao ´ composta base com uma s´erie de m´ odulos adicionais. E por uma m´ aquina virtual, que constitui o ambiente controlado de execu¸ca ˜o das aplica¸c˜ oes, um compilador just-intime, para a linguagem interm´edia, uma API que reproduz as Framework Class Libraries da Microsoft e um compilador de C#. S˜ ao apresentadas, no apˆendice deste documento, listagens de alguns dos exemplos desenvolvidos, sendo que os restantes estar˜ ao dispon´ıveis num ficheiro que dever´ a acompanhar este trabalho.
4.
REFERÊNCIAS
[1] W. Emmerich. Engineering Distributed Objects. John Wiley and Sons, Ltd, 2000. [2] B. et al. Network Objects. DIGITAL, Inc., 1995. [3] G. et al. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, 1995. [4] M. et al. Microsoft .NET Remoting. Microsoft Press, 2003. [5] E. International. Standard ECMA-335: Common Language Infrastructure. ECMA International, 2005. [6] J. Lowy. Managing the lifetime of remote .net objects with leasing and sponsorhip. MSDN Magazine, Dezembro 2003. [7] SUN. Java RMI Specification. Sun Microsystems, Inc., 1998.
APÊNDICES A. LISTAGENS Apresentamos em seguida implementa¸c˜ oes de alguns exemplos desenvolvidos no ˆ ambito de uma demonstra¸c˜ ao das capacidades da plataforma .NET Remoting, conforme detalhadas no texto.
˜ CONCLUSOES
A.1
A infra-estrutura de Remoting, integrada na plataforma .NET, apresenta caracter´ısticas comuns a outros sistemas de objectos distribu´ıdos, n˜ ao alheio ao facto de esta ter sido a abordagem mais recente ao suporte de invoca¸c˜ oes em objectos remotos e toda a problem´ atica em redor. Tal como o CORBA, DCOM e Java/RMI, em Remoting ´e poss´ıvel solicitar a execu¸c˜ ao de opera¸c˜ oes em objectos residentes noutros contextos de execu¸c˜ ao, num ambiente dis` semelhan¸ca do Java/RMI, a inclus˜ tribu´ıdo. A ao no modelo de objectos de objectos n˜ ao-remotos exige uma diferencia¸c˜ ao no seu tratamento a n´ıvel de tipos, e, como nos sistemas acima mencionados, todo o objecto remoto ´e identificado a partir de uma referˆencia que assegura a transparˆencia de localiza¸c˜ ao. A Common Type System estabelece a separa¸c˜ ao entre a no¸c˜ ao de interfaces e implementa¸c˜ oes, e define regras para
Hello World - Client Activated
A.1.1
RemoteObject.cs
using System; using System.Runtime.Remoting; namespace com.mgcm.net.remoting { public class RemoteObject : MarshalByRefObject { public RemoteObject() { } public string HelloWorld() 8
{
using using using using
return "Hello World!"; } }
System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp;
}
A.1.2 using using using using
namespace com.mgcm.net.remoting { public class RemoteClient { public static int Main(string[] args) { TcpChannel tcp = new TcpChannel(); ChannelServices.RegisterChannel(tcp);
RemoteServer.cs System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp;
namespace com.mgcm.net.remoting { public class RemoteServer { public static int Main(string[] args) { TcpChannel tcp = new TcpChannel(8080); ChannelServices.RegisterChannel(tcp);
RemoteObject obj = (RemoteObject) Activator.GetObject( typeof(com.mgcm.net.remoting.RemoteObject), "tcp://localhost:8080/HelloWorld"); Console.WriteLine(obj.HelloWorld()); return 0; }
RemotingConfiguration.RegisterWellKnownServiceType( } } typeof(RemoteObject), "HelloWorld", A.3 WellKnownObjectMode.SingleCall);
A.3.1
System.Console.WriteLine("server running..."); System.Console.ReadLine(); return 0; } }
using using using using
Interfaces.cs
namespace com.mgcm.net.remoting { public interface ITask { void exec(); }
}
A.1.3
Execuc¸a˜ o de C´odigo M´ovel
RemoteClient.cs
public interface IAgent { void run(); }
System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp;
public interface IAgentHost { void accept(IAgent agent); }
namespace com.mgcm.net.remoting { public class RemoteClient { public static int Main(string[] args) { TcpChannel tcp = new TcpChannel(); ChannelServices.RegisterChannel(tcp);
}
A.3.2
Tasks.cs
using System;
RemoteObject obj = (RemoteObject) namespace com.mgcm.net.remoting Activator.CreateInstance( { typeof(com.mgcm.net.remoting.RemoteObject)); [Serializable] public class TaskHello: ITask Console.WriteLine(obj.HelloWorld()); { return 0; public TaskHello():base() } { } } }
A.2 A.2.1
public void exec() { System.Console.WriteLine("Hello World"); }
Hello World - Server Activated RemoteClient.cs 9
A.3.4
}
using System;
[Serializable] public class TaskDateNow: ITask { public TaskDateNow():base() { }
namespace com.mgcm.net.remoting { [Serializable] public class Agent: IAgent { private ITask task;
public void exec() { System.Console.WriteLine(DateTime.Now); }
public Agent(ITask task) { this.task = task; }
} }
A.3.3 using using using using using using
Agent.cs
AgentHost.cs
public void run() { task.exec(); }
System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; System.Collections; System.Threading;
} }
A.3.5
namespace com.mgcm.net.remoting { public class AgentHost: MarshalByRefObject, IAgentHost { private Stack agents;
using using using using
Server.cs System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp;
namespace com.mgcm.net.remoting { public class Server { public static void Main(string[] args) { int port = 8080; TcpChannel channel = new TcpChannel(port) ChannelServices.RegisterChannel(channel);
public AgentHost() { agents = new Stack(); Thread t = new Thread( new ThreadStart(execAgents) ); t.Start(); }
RemotingConfiguration.RegisterWellKnownServiceType( typeof(AgentHost), "AgentHost", WellKnownObjectMode.Singleton );
public void accept(IAgent agent) { agents.Push(agent); }
System.Console.ReadLine();
public void execAgents() { while (true) { if (agents.Count > 0) { IAgent agent = (IAgent) agents.Pop(); Thread t = new Thread( new ThreadStart(agent.run) ); t.Start(); } System.Threading.Thread.Sleep(500); } }
} } }
A.3.6 using using using using
Client.cs System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp;
namespace com.mgcm.net.remoting { public class Client { public static void Main(string[] args) {
} }
10
TcpChannel channel = new TcpChannel(); ChannelServices.RegisterChannel(channel); IAgentHost host = (IAgentHost) Activator.GetObject( typeof(com.mgcm.net.remoting.IAgentHost), "tcp://localhost:8080/AgentHost" ); ITask task1 = ITask task2 = IAgent agent1 IAgent agent2
new TaskHello(); new TaskDateNow(); = new Agent(task1); = new Agent(task2);
host.accept(agent1); host.accept(agent2); } } }
11