Transport: Współdziałanie protokołu TCP z usługami WSE 3.0
Przykład współdziałania protokołu TCP WSE 3.0 pokazuje, jak zaimplementować sesję dwukierunkową TCP jako niestandardowy transport programu Windows Communication Foundation (WCF). Pokazuje również, jak można użyć rozszerzalności warstwy kanału do interfejsu za pośrednictwem przewodu z istniejącymi wdrożonych systemów. W poniższych krokach pokazano, jak utworzyć ten niestandardowy transport WCF:
Począwszy od gniazda TCP, utwórz implementacje IDuplexSessionChannel klienta i serwera, które używają framingu DIME, aby oddzielić granice komunikatów.
Utwórz fabrykę kanałów, która łączy się z usługą TCP WSE i wysyła w ramce komunikaty za pośrednictwem klienta IDuplexSessionChannel.
Utwórz odbiornik kanału w celu akceptowania przychodzących połączeń TCP i tworzenia odpowiednich kanałów.
Upewnij się, że wszystkie wyjątki specyficzne dla sieci są znormalizowane do odpowiedniej klasy pochodnej klasy CommunicationException.
Dodaj element powiązania, który dodaje niestandardowy transport do stosu kanału. Aby uzyskać więcej informacji, zobacz [Dodawanie elementu powiązania].
Tworzenie elementu IDuplexSessionChannel
Pierwszym krokiem na piśmie w programie WSE 3.0 TCP Interoperability Transport jest utworzenie implementacji IDuplexSessionChannel programu na podstawie elementu Socket. WseTcpDuplexSessionChannel
pochodzi z klasy ChannelBase. Logika wysyłania komunikatu składa się z dwóch głównych elementów: (1) Kodowanie komunikatu w bajtach i (2) tworzenie ramek tych bajtów i wysyłanie ich do przewodu.
ArraySegment<byte> encodedBytes = EncodeMessage(message);
WriteData(encodedBytes);
Ponadto blokada jest wykonywana tak, aby wywołania Send() zachowywały gwarancję IDuplexSessionChannel w kolejności i tak, aby wywołania do bazowego gniazda zostały prawidłowo zsynchronizowane.
WseTcpDuplexSessionChannel
używa elementu MessageEncoder do tłumaczenia elementu Message do i z bajtu[]. Ponieważ jest to transport, jest również odpowiedzialny za zastosowanie adresu zdalnego, WseTcpDuplexSessionChannel
z którego skonfigurowano kanał. EncodeMessage
hermetyzuje logikę dla tej konwersji.
this.RemoteAddress.ApplyTo(message);
return encoder.WriteMessage(message, maxBufferSize, bufferManager);
Po zakodowaniu Message w bajtach należy go przekazać w przewodzie. Wymaga to systemu do definiowania granic komunikatów. WSE 3.0 używa wersji DIME jako protokołu framingu. WriteData
Hermetyzuje logikę tworzenia ramek w celu zawijania bajtu[] do zestawu rekordów DIME.
Logika odbierania komunikatów jest podobna. Główną złożonością jest obsługa faktu, że odczyt gniazda może zwrócić mniej bajtów niż zażądano. Aby odebrać komunikat, WseTcpDuplexSessionChannel
odczytuje bajty z przewodu, dekoduje ramkę DIME, a następnie używa MessageEncoder elementu do przekształcania bajtu[] w Message.
W bazie WseTcpDuplexSessionChannel
przyjęto założenie, że otrzymuje połączone gniazdo. Klasa bazowa obsługuje zamykanie gniazd. Istnieją trzy miejsca, które zapewniają interfejs z zamknięciem gniazda:
OnAbort - zamknij gniazdo niegrzecznie (twarde zamknięcie).
Na[Początek]Zamknij - zamknij gniazdo bezpiecznie (miękkie zamknięcie).
Sesji. CloseOutputSession — zamknij strumień danych wychodzących (połowa zamknięcia).
Fabryka kanałów
Następnym krokiem podczas pisania transportu TCP jest utworzenie implementacji kanałów klienckich IChannelFactory .
WseTcpChannelFactory
pochodzi z ChannelFactoryBase<IDuplexSessionChannel>. Jest to fabryka, która zastępujeOnCreateChannel
tworzenie kanałów klienckich.
protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
{
return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);
}
ClientWseTcpDuplexSessionChannel
dodaje logikę do bazyWseTcpDuplexSessionChannel
w celu nawiązania połączenia z serwerem TCP wchannel.Open
czasie. Najpierw nazwa hosta jest rozpoznawana jako adres IP, jak pokazano w poniższym kodzie.
hostEntry = Dns.GetHostEntry(Via.Host);
- Następnie nazwa hosta jest połączona z pierwszym dostępnym adresem IP w pętli, jak pokazano w poniższym kodzie.
IPAddress address = hostEntry.AddressList[i];
socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(address, port));
- W ramach kontraktu kanału wszystkie wyjątki specyficzne dla domeny są opakowane, takie jak
SocketException
w pliku CommunicationException.
Odbiornik kanału
Następnym krokiem podczas pisania transportu TCP jest utworzenie implementacji akceptowania IChannelListener kanałów serwera.
WseTcpChannelListener
pochodzi z ChannelListenerBase<IDuplexSessionChannel> i zastępuje on[Begin]Open i On[Begin]Close, aby kontrolować okres istnienia gniazda nasłuchiwania. W obszarze OnOpen jest tworzone gniazdo do nasłuchiwania na IP_ANY. Bardziej zaawansowane implementacje mogą również utworzyć drugie gniazdo do nasłuchiwania przy użyciu protokołu IPv6. Mogą również zezwalać na określenie adresu IP w nazwie hosta.
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);
Po zaakceptowaniu nowego gniazda kanał serwera jest inicjowany za pomocą tego gniazda. Wszystkie dane wejściowe i wyjściowe są już implementowane w klasie bazowej, więc ten kanał jest odpowiedzialny za inicjowanie gniazda.
Dodawanie elementu powiązania
Teraz, gdy fabryki i kanały zostały skompilowane, muszą być uwidocznione w środowisku uruchomieniowym Usługi ServiceModel za pomocą powiązania. Powiązanie to kolekcja elementów powiązania, które reprezentują stos komunikacji skojarzony z adresem usługi. Każdy element w stosie jest reprezentowany przez element powiązania.
W przykładzie element powiązania to WseTcpTransportBindingElement
, który pochodzi z elementu TransportBindingElement. Obsługuje IDuplexSessionChannel ona i zastępuje następujące metody tworzenia fabryk skojarzonych z naszym powiązaniem.
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);
}
Zawiera również elementy członkowskie do klonowania i zwracania naszego schematu BindingElement
(wse.tcp).
Konsola testowa PROTOKOŁU TCP programu WSE
Kod testowy do korzystania z tego przykładowego transportu jest dostępny w TestCode.cs. Poniższe instrukcje pokazują, jak skonfigurować przykład WSE TcpSyncStockService
.
Kod testowy tworzy niestandardowe powiązanie, które używa modelu MTOM jako kodowania i WseTcpTransport
transportu. Konfiguruje również element AddressingVersion zgodny z programem WSE 3.0, jak pokazano w poniższym kodzie.
CustomBinding binding = new CustomBinding();
MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();
mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;
binding.Elements.Add(mtomBindingElement);
binding.Elements.Add(new WseTcpTransportBindingElement());
Składa się z dwóch testów — jeden test konfiguruje typizowanego klienta przy użyciu kodu wygenerowanego na podstawie WSDL programu WSE 3.0. Drugi test używa usługi WCF zarówno jako klienta, jak i serwera, wysyłając komunikaty bezpośrednio na podstawie interfejsów API kanału.
Podczas uruchamiania przykładu oczekiwane są następujące dane wyjściowe.
Klient:
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.
Serwer:
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
Konfigurowanie, kompilowanie i uruchamianie przykładu
- Aby uruchomić ten przykład, musisz mieć zainstalowane ulepszenia usług sieci Web (WSE) 3.0 dla platformy Microsoft .NET i przykład programu WSE
TcpSyncStockService
.
Uwaga
Ponieważ program WSE 3.0 nie jest obsługiwany w systemie Windows Server 2008, nie można zainstalować ani uruchomić przykładu TcpSyncStockService
w tym systemie operacyjnym.
Po zainstalowaniu przykładu
TcpSyncStockService
wykonaj następujące czynności:Otwórz plik
TcpSyncStockService
w programie Visual Studio. (Przykład TcpSyncStockService jest instalowany z programem WSE 3.0. Nie jest częścią kodu tego przykładu).Ustaw projekt StockService jako projekt startowy.
Otwórz StockService.cs w projekcie StockService i oznacz jako komentarz atrybut [Policy] w
StockService
klasie. Spowoduje to wyłączenie zabezpieczeń z przykładu. Chociaż program WCF może współpracować z bezpiecznymi punktami końcowymi programu WSE 3.0, zabezpieczenia są wyłączone, aby zachować ten przykład skoncentrowany na niestandardowym transporcie TCP.naciśnij klawisz F5, aby uruchomić .
TcpSyncStockService
Usługa jest uruchamiana w nowym oknie konsoli.Otwórz ten przykład transportu TCP w programie Visual Studio.
Zaktualizuj zmienną "hostname" w TestCode.cs, aby odpowiadała nazwie komputera z uruchomioną wartością
TcpSyncStockService
.naciśnij klawisz F5 , aby uruchomić przykład transportu TCP.
Klient testowy transportu TCP jest uruchamiany w nowej konsoli. Klient żąda ofert giełdowych z usługi, a następnie wyświetla wyniki w oknie konsoli.