Compartilhar via


Transporte: interoperabilidade de TCP de WSE 3.0

O exemplo de Transporte de interoperabilidade de TCP no WSE 3.0 demonstra como implementar uma sessão duplex de TCP como um transporte personalizado do WCF (Windows Communication Foundation). Também demonstra como você pode usar a extensibilidade da camada de canal para fazer a interface pelo fio com sistemas implantados existentes. As etapas a seguir mostram como criar este transporte personalizado no WCF:

  1. Começando com um soquete de TCP, crie implementações de cliente e servidor de IDuplexSessionChannel que usam o Enquadramento DIME para delinear limites de mensagem.

  2. Crie uma fábrica de canais que se conecte a um serviço TCP do WSE e envie mensagens emolduradas pelos IDuplexSessionChannel do cliente.

  3. Crie um ouvinte de canais para aceitar conexões TCP de entrada e produzir canais correspondentes.

  4. Confirme que quaisquer exceções específicas à rede sejam normalizadas para a classe derivada apropriada de CommunicationException.

  5. Adicione um elemento de associação que acrescenta o transporte personalizado a uma pilha de canais. Para saber mais, confira [Adição de um elemento de associação].

Criação de IDuplexSessionChannel

A primeira etapa na gravação do Transporte de Interoperabilidade TCP no WSE 3.0 é criar uma implementação de IDuplexSessionChannel sobre um Socket. WseTcpDuplexSessionChannel deriva de ChannelBase. A lógica de enviar uma mensagem consiste em duas partes principais: (1) Codificação da mensagem em bytes e (2) enquadramento desses bytes e enviá-los por transferência.

ArraySegment<byte> encodedBytes = EncodeMessage(message);

WriteData(encodedBytes);

Além disso, um bloqueio é feito para que as chamadas Send() preservem a garantia de ordem de IDuplexSessionChannel, para que as chamadas para o soquete subjacente sejam sincronizadas corretamente.

WseTcpDuplexSessionChannel usa um MessageEncoder para converter um Message de e para byte[]. Como é um transporte, WseTcpDuplexSessionChannel também é responsável por aplicar o endereço remoto com o qual o canal foi configurado. EncodeMessage encapsula a lógica dessa conversão.

this.RemoteAddress.ApplyTo(message);

return encoder.WriteMessage(message, maxBufferSize, bufferManager);

Depois que o Message é codificado em bytes, ele deve ser transmitido. Isso requer um sistema para definição de limites de mensagem. O WSE 3.0 usa uma versão do DIME como seu protocolo de enquadramento. WriteData encapsula a lógica de enquadramento para encapsular um byte[] em um conjunto de registros DIME.

A lógica para receber mensagens é semelhante. A principal complexidade é lidar com o fato de que uma leitura de soquete pode retornar menos bytes do que o solicitado. Para receber uma mensagem, o WseTcpDuplexSessionChannel lê bytes na transmissão, decodifica o enquadramento DIME e usa o MessageEncoder para transformar o byte[] em um Message.

A base WseTcpDuplexSessionChannel pressupõe que ela receba um soquete conectado. A classe base manipula o desligamento do soquete. Há três locais que fazem interface com o fechamento do soquete:

  • OnAbort -- fecha o soquete de forma desajeitada (fechamento forçado).

  • On[Begin]Close -- fecha o soquete normalmente (fechamento suave).

  • session.CloseOutputSession -- desliga o fluxo de dados de saída (meio fechamento).

Fábrica de canais

A próxima etapa na gravação do transporte TCP é criar uma implementação de IChannelFactory para canais do cliente.

  • WseTcpChannelFactory deriva de ChannelFactoryBase<IDuplexSessionChannel>. É uma fábrica que substitui OnCreateChannel para produzir canais de cliente.

protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)

{

return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);

}

  • ClientWseTcpDuplexSessionChannel adiciona lógica à base WseTcpDuplexSessionChannel para se conectar a um servidor TCP no momento de channel.Open. Primeiro, o nome do host é resolvido para um endereço IP, conforme mostrado no código a seguir.

hostEntry = Dns.GetHostEntry(Via.Host);

  • Em seguida, o nome do host é conectado ao primeiro endereço IP disponível em um loop, conforme mostrado no código a seguir.

IPAddress address = hostEntry.AddressList[i];

socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(new IPEndPoint(address, port));

  • Como parte do contrato de canal, todas as exceções específicas do domínio são encapsuladas, como SocketException em CommunicationException.

Ouvinte de canais

A próxima etapa na gravação do transporte TCP é criar uma implementação de IChannelListener para aceitar canais do servidor.

  • WseTcpChannelListener deriva de ChannelListenerBase<IDuplexSessionChannel> e substitui On[Begin]Open e On[Begin]Close para controlar o tempo de vida de seu soquete de escuta. No OnOpen, um soquete é criado para escutar em IP_ANY. Implementações mais avançadas também podem criar um segundo soquete para escutar no IPv6. Elas também podem permitir que o endereço IP seja especificado no nome do host.

IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, uri.Port);

this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

this.listenSocket.Bind(localEndpoint);

this.listenSocket.Listen(10);

Quando um novo soquete é aceito, um canal de servidor é inicializado com esse soquete. Entrada e saída já estão implementadas na classe base, portanto, esse canal é responsável por inicializar o soquete.

Adicionar um elemento de associação

Agora que as fábricas e os canais foram criados, eles devem ser expostos ao runtime do ServiceModel por meio de uma associação. Uma associação é uma coleção de elementos de associação que representa a pilha de comunicação associada a um endereço de serviço. Cada elemento na pilha é representado por um elemento de associação.

No exemplo, o elemento de associação é WseTcpTransportBindingElement, que deriva de TransportBindingElement. Ele dá suporte a IDuplexSessionChannel e substitui os métodos a seguir para criar as fábricas associadas à nossa associação.

public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)

{

return (IChannelFactory<TChannel>)(object)new WseTcpChannelFactory(this, context);

}

public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)

{

return (IChannelListener<TChannel>)(object)new WseTcpChannelListener(this, context);

}

Também contém membros para clonar o BindingElement e retornar nosso esquema (wse.tcp).

O console de teste de TCP no WSE

O código de teste para usar esse transporte de exemplo está disponível em TestCode.cs. As instruções a seguir mostram como configurar o exemplo de TcpSyncStockService do WSE.

O código de teste cria uma associação personalizada que usa MTOM como codificação e WseTcpTransport como transporte. Também configura o AddressingVersion para estar em conformidade com o WSE 3.0, conforme mostrado no código a seguir.

CustomBinding binding = new CustomBinding();

MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();

mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;

binding.Elements.Add(mtomBindingElement);

binding.Elements.Add(new WseTcpTransportBindingElement());

Ele é composto por dois testes – um teste configura um cliente tipado usando o código gerado a partir do WSDL no WSE 3.0. O segundo teste usa o WCF como o cliente e o servidor enviando mensagens diretamente sobre as APIs do canal.

Ao executar o exemplo, a saída a seguir é esperada.

Cliente:

Calling soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Symbol: FABRIKAM
        Name: Fabrikam, Inc.
        Last Price: 120

Symbol: CONTOSO
        Name: Contoso Corp.
        Last Price: 50.07
Press enter.

Received Action: http://SayHello
Received Body: to you.
Hello to you.
Press enter.

Received Action: http://NotHello
Received Body: to me.
Press enter.

Servidor:

Listening for messages at soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Press any key to exit when done...

Request received.
Symbols:
        FABRIKAM
        CONTOSO

Configurar, compilar e executar a amostra

  1. Para executar este exemplo, você deve ter o WSE (Web Services Enhancements) 3.0 para o Microsoft .NET e o exemplo TcpSyncStockService do WSE instalados.

Observação

Como o WSE 3.0 não tem suporte no Windows Server 2008, você não pode instalar ou executar o exemplo TcpSyncStockService nesse sistema operacional.

  1. Depois de instalar o exemplo TcpSyncStockService, faça o seguinte:

    1. Abra o TcpSyncStockService no Visual Studio. (O exemplo TcpSyncStockService é instalado com o WSE 3.0. Ele não faz parte do código deste exemplo.)

    2. Defina o projeto StockService como o projeto inicialização.

    3. Abra StockService.cs no projeto StockService e comente o atributo [Policy] na classe StockService. Isso desabilita a segurança do exemplo. Embora o WCF possa interoperar com pontos de extremidade seguros do WSE 3.0, a segurança está desabilitada para manter esse exemplo focado no transporte de TCP personalizado.

    4. pressione F5 para iniciar o TcpSyncStockService. O serviço inicia em uma nova janela de console.

    5. Abra este exemplo de transporte TCP no Visual Studio.

    6. Atualize a variável "hostname" em TestCode.cs para corresponder ao nome do computador que executa o TcpSyncStockService.

    7. pressione F5 para iniciar o exemplo de transporte de TCP.

    8. O cliente de teste de transporte de TCP é iniciado em um novo console. O cliente solicita cotações de ações ao serviço e exibe os resultados na janela do console.