Udostępnij za pośrednictwem


Wybieranie wzorca wymiany komunikatów

Pierwszym krokiem w pisaniu transportu niestandardowego jest podjęcie decyzji, które wzorce wymiany komunikatów (lub deputowanych) są wymagane dla opracowywanego kanału. W tym temacie opisano dostępne opcje i omówiono różne wymagania. Jest to pierwsze zadanie na liście zadań tworzenia kanału opisane w temacie Tworzenie kanałów.

Sześć wzorców wymiany komunikatów

Spośród trzech posłów do PE należy wybrać:

  • Datagram (IInputChannel i IOutputChannel)

    W przypadku korzystania z datagramu MEP klient wysyła komunikat przy użyciu ognia i zapomnij wymiany. Transakcja „wystrzel i zapomnij” to taka, która wymaga potwierdzenia poza kanałem, że dostarczenie było pomyślne. Wiadomość może zostać utracona podczas przesyłania i nigdy nie dociera do usługi. Jeśli operacja wysyłania zakończy się pomyślnie po stronie klienta, nie gwarantuje, że zdalny odbiorca odebrał komunikat. Datagram jest podstawowym blokiem konstrukcyjnym do obsługi komunikatów, ponieważ można tworzyć własne protokoły, w tym niezawodne protokoły i bezpieczne protokoły. Kanały datagramu klienta implementują IOutputChannel interfejs i kanały datagramu usługi implementują IInputChannel interfejs.

  • Request-Response (IRequestChannel i IReplyChannel)

    W tym MEP wysyła się wiadomość, a odpowiedź jest otrzymywana. Wzorzec składa się z par żądań-odpowiedzi. Przykłady wywołań typu żądanie-odpowiedź to zdalne wywołania procedur (RPC) i żądania GET przeglądarki. Ten wzorzec jest również nazywany półdupleksem. W tym MEP kanały klienta implementują IRequestChannel, a kanały usług implementują IReplyChannel.

  • Dupleks (IDuplexChannel)

    Dupleksowy wzorzec wymiany wiadomości umożliwia przesyłanie przez klienta dowolnej liczby komunikatów i odbieranie ich w dowolnej kolejności. Dwudupleksowy poseł do PE jest jak rozmowa telefoniczna, gdzie każde słowo mówione jest wiadomością. Ponieważ w tym MEP obie strony mogą zarówno wysyłać, jak i odbierać, interfejs implementowany przez klienta oraz kanały usług jest IDuplexChannel.

Schemat blokowy przedstawiający trzy podstawowe wzorce wymiany komunikatów
Trzy podstawowe wzorce wymiany komunikatów. Od góry do dołu: datagram, żądanie-odpowiedź i dupleks.

Każdy z tych posłów może również wspierać sesje. Sesja (i implementacja System.ServiceModel.Channels.ISessionChannel<TSession> typu System.ServiceModel.Channels.ISession) powiązuje wszystkie komunikaty wysyłane i odbierane na kanale. Wzorzec odpowiedzi na żądanie jest autonomiczną sesją z dwoma komunikatami, ponieważ żądanie i odpowiedź są skorelowane. Z kolei wzorzec żądania-odpowiedzi, który obsługuje sesje, oznacza, że wszystkie pary żądań/odpowiedzi w tym kanale są skorelowane ze sobą. Daje to w sumie sześciu posłów do parlamentu do wyboru:

  • Datagram

  • Żądanie-odpowiedź

  • Mieszkanie dwupoziomowe

  • Datagram z sesjami

  • Mechanizm żądanie-odpowiedź z sesjami.

  • Dupleks z sesjami

Uwaga / Notatka

W przypadku transportu UDP jedynym obsługiwanym mechanizmem wymiany wiadomości (MEP) jest datagram, ponieważ UDP jest z natury protokołem bez potwierdzenia.

Sesje i kanały sesjowe

W świecie sieci istnieją protokoły zorientowane na połączenie (na przykład TCP) i protokoły bez połączenia (na przykład UDP). WCF używa terminu sesji w znaczeniu abstrakcji logicznej podobnej do połączenia. Sesjowe protokoły WCF są podobne do protokołów sieciowych zorientowanych na połączenie, a protokoły WCF bez sesji są podobne do protokołów sieciowych bez połączenia.

W modelu obiektowym kanału każda sesja logiczna objawia się jako wystąpienie kanału pełnego sesji. W związku z tym każda nowa sesja utworzona przez klienta i zaakceptowana przez usługę odpowiada nowemu kanałowi sesji po obu stronach. Na poniższym diagramie u góry przedstawiono strukturę kanałów bez sesji, a u dołu strukturę kanałów z sesjami.

Schemat blokowy przedstawiający strukturę kanałów sesyjnych oraz bez sesji

Klient tworzy nowy kanał z sesją i wysyła wiadomość. Po stronie usługi nasłuchiwacz kanału odbiera ten komunikat i wykrywa, że należy do nowej sesji, więc tworzy nowy kanał sesji i przekazuje go aplikacji (w odpowiedzi na wywołanie przez aplikację AcceptChannel na nasłuchiwaczu kanału). Następnie aplikacja odbiera ten komunikat i wszystkie kolejne komunikaty wysyłane w tej samej sesji za pośrednictwem tego samego kanału sesji.

Inny klient (lub ten sam klient) tworzy nową sesję i wysyła komunikat. Odbiornik kanału wykrywa, że ten komunikat znajduje się w nowej sesji, tworzy nowy kanał stanowy i proces się powtarza.

Bez sesji nie ma korelacji między kanałami i sesjami. W związku z tym odbiornik kanału tworzy tylko jeden kanał, za pośrednictwem którego wszystkie odebrane komunikaty są dostarczane do aplikacji. Nie ma również kolejności komunikatów, ponieważ nie ma sesji, w ramach której należy zachować kolejność komunikatów. Górna część powyższej grafiki ilustruje wymianę komunikatów bez sesji.

Uruchamianie i kończenie sesji

Sesje są uruchamiane na kliencie poprzez proste utworzenie nowego kanału sesyjnego. Są one uruchamiane w usłudze, gdy usługa odbiera komunikat, który został wysłany w nowej sesji. Podobnie sesje są przerywane przez zamknięcie lub przerwanie kanału pełnego sesji.

Wyjątek od tego stanowi IDuplexSessionChannel, który jest używany zarówno do wysyłania, jak i odbierania wiadomości w dupleksowym, sesyjnym wzorcu komunikacji. Istnieje możliwość, że jedna strona będzie chciała przestać wysyłać komunikaty, ale nadal je odbierać, dlatego korzystając z IDuplexSessionChannel, jest mechanizm, który umożliwia zamknięcie sesji wyjściowej, co wskazuje, że nie będą wysyłane więcej komunikatów, ale pozwala zachować otwartą sesję wejściową, umożliwiając kontynuowanie odbierania komunikatów.

Ogólnie rzecz biorąc, sesje są zamykane po stronie wychodzącej, a nie po stronie przychodzącej. Oznacza to, że kanały wyjściowe z sesji można zamknąć, co umożliwia czyste zakończenie sesji. Zamknięcie kanału wyjściowego posiadającego sesję powoduje, że odpowiedni kanał wejściowy posiadający sesję zwraca wartość null do aplikacji wywołującej IInputChannel.ReceiveIDuplexSessionChannel.

Jednak kanały wejściowe sesji nie powinny być zamykane, z wyjątkiem sytuacji, gdy IInputChannel.Receive zwraca wartość null w IDuplexSessionChannel, co oznacza, że sesja jest już zamknięta. Jeśli IInputChannel.Receive w IDuplexSessionChannel nie zwróciło wartości null, zamknięcie sesyjnego kanału wejściowego może zgłosić wyjątek, ponieważ podczas zamykania może odbierać nieoczekiwane komunikaty. Jeśli odbiorca chce zakończyć sesję przed nadawcą, powinien wywołać Abort na kanale wejściowym, co nagle kończy sesję.

Tworzenie kanałów z sesjami

Jako autor kanału obsługującego sesje, istnieje kilka rzeczy, które Twój kanał musi zrobić, aby zapewnić sesje. Po stronie wysyłania kanał musi:

  • Dla każdego nowego kanału utwórz nową sesję i skojarz ją z nowym identyfikatorem sesji, który jest unikatowym ciągiem. Możesz też uzyskać nową sesję z kanału pełnego sesji niżej w stosie.

  • Dla każdego komunikatu wysyłanego przy użyciu tego kanału, jeśli kanał utworzył sesję (w przeciwieństwie do uzyskania go z poniższej warstwy), musisz skojarzyć komunikat z sesją. W przypadku kanałów protokołu zazwyczaj odbywa się to przez dodanie nagłówka SOAP. W przypadku kanałów transportowych zazwyczaj odbywa się to przez utworzenie nowego połączenia transportowego lub dodanie informacji o sesji do protokołu framingu.

  • Dla każdego komunikatu wysyłanego przy użyciu tego kanału należy podać gwarancje dostarczania wymienione powyżej. Jeśli polegasz na kanale poniżej, aby udostępnić sesję, ten kanał zapewni również gwarancje dostarczenia. Jeśli udostępniasz sesję samodzielnie, musisz zaimplementować te gwarancje w ramach protokołu. Ogólnie rzecz biorąc, jeśli piszesz kanał protokołu z założeniem, że usługi WCF są aktywne po obu stronach, możesz potrzebować transportu TCP lub kanału Niezawodnego przesyłania wiadomości i polegać na jednym z nich, aby zapewnić sesję.

  • Gdy ICommunicationObject.Close zostanie wywołany na Twoim kanale, wykonaj niezbędne kroki, aby zamknąć sesję, używając określonego limitu czasu lub domyślnego. Może to być tak proste, jak wywołanie Close na kanale poniżej ciebie (jeśli właśnie otrzymałeś z niego sesję) lub wysłanie specjalnej wiadomości SOAP albo zamknięcie połączenia transportowego.

  • Gdy Abort jest wywołane dla Twojego kanału, zakończ sesję nagle bez wykonywania operacji wejścia-wyjścia. Może to oznaczać, że nic nie robi lub może wymagać przerwania połączenia sieciowego lub innego zasobu.

Po stronie odbioru, kanał musi:

  • Dla każdego przychodzącego komunikatu odbiornik kanału musi wykryć sesję, do którego należy. Jeśli jest to pierwszy komunikat w sesji, odbiornik kanału musi utworzyć nowy kanał i zwrócić go z wywołania do IChannelListener<TChannel>.AcceptChannel. W przeciwnym razie odbiornik kanału musi znaleźć istniejący kanał odpowiadający sesji i dostarczyć komunikat za pośrednictwem tego kanału.

  • Jeśli twój kanał udostępnia sesję (wraz z wymaganymi gwarancjami dostarczania), strona odbierania może być wymagana do wykonania niektórych akcji, takich jak ponowne zamawianie komunikatów lub wysyłanie potwierdzeń.

  • Gdy Close zostanie wywołane na Twoim kanale, wykonaj niezbędną pracę, aby zamknąć sesję przed upływem określonego limitu czasu lub domyślnego. Może to spowodować wyjątki, jeśli kanał odbierze komunikat podczas oczekiwania na wygaśnięcie limitu czasu zamknięcia. Dzieje się tak, ponieważ kanał będzie w stanie Zamykanie po odebraniu komunikatu, aby został zgłoszony.

  • Gdy Abort jest wywołane dla Twojego kanału, zakończ sesję nagle bez wykonywania operacji wejścia-wyjścia. Ponownie może to oznaczać, że nic nie robi lub może wymagać przerwania połączenia sieciowego lub innego zasobu.

Zobacz także