다음을 통해 공유


싱크 및 싱크 체인

채널에서는 메시지를 보내기 전이나 메시지를 받은 후에 각 메시지를 채널 싱크 개체의 체인과 함께 보냅니다. 이 싱크 체인에는 기본 채널 기능에 필요한 포맷터, 전송 또는 스택 작성기 싱크 등의 싱크가 포함되어 있지만 채널 싱크 체인을 사용자 지정하여 메시지 또는 스트림과 관련된 특수 작업을 수행할 수 있습니다.

각 채널 싱크에서는 IClientChannelSink 또는 IServerChannelSink 중 하나를 구현합니다. 클라이언트측의 첫 번째 채널 싱크에서는 IMessageSink도 구현해야 합니다. 일반적으로 이 싱크는 IMessageSink, IChannelSinkBaseIClientChannelSink에서 상속하는 IClientFormatterSink를 구현하며, 들어오는 메시지를 스트림 즉, IMessage 개체로 변환하기 때문에 포맷터 싱크라고 합니다.

채널 싱크 체인에서는 응용 프로그램 도메인과 주고 받는 모든 메시지를 처리합니다. 이 시점에서 사용자가 받는 것은 메시지뿐이지만 해당 메시지로 필요한 모든 작업을 수행할 수 있으며 후속 처리에서는 처리 후 사용자가 시스템에 반환하는 메시지를 사용합니다. 채널 싱크 체인은 로깅 서비스, 필터 정렬이나 클라이언트 또는 서버측의 암호화 또는 기타 보안 수단을 구현하는 일반적인 위치입니다. 다음 그림에서는 기본 채널 싱크 체인의 구조를 보여 줍니다.

기본 채널 싱크 체인

기본 채널 싱크 체인

각 채널 싱크에서는 스트림을 처리한 다음 이 스트림을 다음 채널 싱크에 전달합니다. 따라서 해당 싱크의 앞 또는 뒤에 있는 개체에서는 사용자가 전달한 스트림에 대해 수행할 작업을 알아야 합니다.

참고

메시지 싱크에서는 예외를 Throw하면 안 됩니다. 메시지 싱크에서 이를 제어할 수 있는 한 가지 방법은 메서드 코드를 try-catch 블록에 래핑하는 것입니다.

IClientChannelSinkProvider, IClientFormatterSinkProvider 또는 IServerChannelSinkProvider 인터페이스를 구현하는 개체인 채널 싱크 공급자는 원격 메시지가 통과하는 채널 싱크를 만듭니다. 원격 형식이 활성화되면 채널에서 채널 싱크 공급자가 검색되고 해당 싱크 공급자에 대해 CreateSink 메서드가 호출되어 체인에서 첫 번째 채널 싱크를 검색합니다.

채널 싱크에서는 클라이언트와 서버 간에 메시지를 전송합니다. 채널 싱크는 체인에서 서로 연결되기도 합니다. 싱크 공급자에 대해 CreateSink 메서드를 호출하면 이 메서드는 다음을 수행해야 합니다.

  • 자체 채널 싱크를 만듭니다.

  • 체인에 있는 다음 싱크 공급자에 대해 CreateSink를 호출합니다.

  • 다음 싱크와 현재 싱크가 서로 연결되어 있는지 확인합니다.

  • 해당 싱크를 호출자에게 반환합니다.

채널 싱크에서는 해당 채널 싱크에 대한 모든 호출을 체인에 있는 다음 싱크로 전달하므로 다음 싱크에 대한 참조를 저장하기 위한 메커니즘이 있어야 합니다.

채널 싱크는 싱크 체인에서 순차적으로 메시지를 보낸다는 점에서 큰 유연성이 있습니다. 예를 들어, 실제로 serialize된 원본 메시지를 보내기 전에 인증을 조정하려는 보안 싱크에서는 전체 채널 메시지를 계속 보유하다가 콘텐츠 스트림을 자체 콘텐츠로 대체한 다음 싱크 체인으로 보내 원격 응용 프로그램 도메인에 전달할 수 있습니다. 반환 과정에서 보안 싱크는 응답 메시지를 차단하고 원격 응용 프로그램 도메인에 있는 해당 보안 싱크와 필요한 사항을 조정합니다. 동의에 이르면 원래 보안 싱크에서 원본 콘텐츠 스트림을 원격 응용 프로그램 도메인에 보낼 수 있습니다.

채널 싱크 체인에서의 메시지 처리

.NET Remoting 시스템에서 IMethodCallMessage 구현을 처리할 수 있는 채널을 찾고 나면 이 채널에서는 IMessageSink.SyncProcessMessage 또는 IMessageSink.AsyncProcessMessage를 호출하여 포맷터 채널 싱크에 메시지를 전달합니다. 포맷터 싱크에서는 전송 헤더 배열을 만들고 다음 싱크에 대해 IClientChannelSink.GetRequestStream을 호출합니다. 이 호출은 싱크 싱크 체인으로 전달되며 모든 싱크에서 포맷터 싱크에 다시 전달할 요청 스트림을 만들 수 있습니다. GetRequestStream이 null 참조(Visual Basic에서는 Nothing)를 반환하는 경우 포맷터 싱크에서는 자체 싱크를 만들어 serialization에 사용합니다. 이 호출이 반환되면 메시지가 serialize되고 싱크 체인의 첫 번째 채널 싱크에 대해 적절한 메시지 처리 메서드가 호출됩니다.

싱크에서는 데이터를 스트림에 쓸 수 없지만 스트림에서 데이터를 읽거나 필요한 경우 새 스트림을 함께 전달할 수는 있습니다. 싱크에서는 다음 싱크에 대해 아직 GetRequestStream을 호출하지 않은 경우 헤더 배열에 헤더를 추가하고, 다음 싱크에 호출을 전달하기 전에 싱크 스택에 자신을 추가할 수도 있습니다. 호출이 체인의 끝에 있는 전송 싱크에 도달하면 전송 싱크에서는 채널을 통해 헤더와 serialize된 메시지를 서버에 보냅니다. 이 메시지를 받은 서버에서는 전체 프로세스가 반대로 수행됩니다. 서버측의 전송 싱크에서는 스트림의 서버측에서 헤더와 serialize된 메시지를 검색하고 포맷터 싱크에 도달할 때까지 싱크 체인을 통해 이를 전달합니다. 포맷터 싱크에서는 메시지를 deserialize하여 원격 시스템으로 전달하고, 원격 시스템에서는 이 메시지를 다시 메서드 호출로 전환하여 서버 개체에 대해 호출합니다.

채널 싱크 체인 만들기

새 채널 싱크를 만들려면 사용자 지정 IClientChannelSink 또는 IServerChannelSink 구현을 만들거나 체인에 있는 다음 싱크를 검색할 수 있는 IServerChannelSinkProvider 또는 IClientChannelSinkProvider 구현을 인식하도록 원격 시스템을 구현하고 구성해야 합니다. BaseChannelSinkWithProperties 추상 클래스를 사용하여 사용자 지정 채널 싱크를 구현할 수 있습니다.

채널 싱크 공급자 빌드

응용 프로그램에서는 채널을 생성할 때 서버 또는 클라이언트 채널 싱크 공급자를 매개 변수로 제공할 수 있습니다. 채널 싱크 공급자는 체인에 저장되어야 하며 사용자는 채널 생성자에 외부 채널 싱크 공급자를 전달하기 전에 모든 채널 싱크 공급자를 연결해야 합니다. 채널 싱크 공급자는 이러한 목적에 사용하는 Next 속성을 구현합니다. 다음 코드 예에서는 클라이언트측 채널 싱크 공급자의 빌드 방법을 보여 줍니다. 전체 예는 원격 서비스 예: 채널 싱크 공급자를 참조하십시오.

private Function CreateDefaultClientProviderChain() As IClientChannelSinkProvider
   Dim chain As New FirstClientFormatterSinkProvider            
   Dim sink As IClientChannelSinkProvider
   sink = chain
   sink.Next = New SecondClientFormatterSinkProvider
   sink = sink.Next
   return chain
End Function 
private IClientChannelSinkProvider CreateDefaultClientProviderChain(){
   IClientChannelSinkProvider chain = new FirstClientFormatterSinkProvider();            
   IClientChannelSinkProvider sink = chain;
   sink.Next = new SecondClientFormatterSinkProvider();
   sink = sink.Next;
   return chain;
} 

참고

구성 파일에 여러 개의 채널 싱크 공급자가 제공된 경우 원격 시스템에서는 구성 파일에 나타나는 순서대로 채널 싱크 공급자를 연결합니다. RemotingConfiguration.Configure를 호출할 때 채널이 만들어지면 채널 싱크 공급자가 만들어집니다.

포맷터 싱크

포맷터 싱크에서는 채널 메시지를 메시지 스트림에 IMessage를 구현하는 개체로 serialize합니다. 일부 포맷터 싱크 구현에서는 시스템에서 제공하는 포맷터 형식인 BinaryFormatterSoapFormatter를 사용합니다. 다른 구현에서는 고유의 방법을 사용하여 채널 메시지를 스트림으로 변환합니다.

포맷터 싱크의 기능은 필요한 헤더를 생성하고 메시지를 스트림으로 serialize하는 것입니다. 포맷터 싱크 다음에는 메시지가 IMessageSink.ProcessMessage 또는 Imessagesink.AsyncProcessMessage 호출을 통해 싱크 체인에 있는 모든 싱크에 전달됩니다. 이 단계에서 메시지는 이미 serialize되어 있으며 정보로만 제공됩니다.

참고

메시지 자체를 만들거나 수정해야 하는 싱크는 싱크 체인에서 포맷터 앞에 놓여야 합니다. IClientFormatterSink를 구현하면 이를 쉽게 수행할 수 있으며, 시스템에서 해당 싱크에 포맷터 싱크에 대한 참조가 있는 것으로 믿게 할 수 있습니다. 그런 다음에는 실제 포맷터 싱크를 싱크 체인에서 다음 위치에 놓을 수 있습니다.

반환 과정에서 포맷터 싱크는 메시지 스트림을 다시 채널 메시지 요소(반환 메시지)로 변환합니다. 클라이언트측의 첫 번째 싱크에서는 IClientFormatterSink 인터페이스를 구현해야 합니다. CreateSink가 채널에 반환할 때 반환되는 참조는 IMessage 인터페이스의 SyncProcessMessage가 호출될 수 있도록 IClientFormatterSink 형식으로 변환됩니다. 형식 변환에 실패하면 시스템에서는 예외를 발생시킵니다.

사용자 지정 채널 싱크

클라이언트측에서 사용자 지정 채널 싱크는 개체 체인에서 포맷터 싱크와 마지막 전송 싱크 사이에 삽입됩니다. 클라이언트 또는 서버 채널에 사용자 지정 채널 싱크를 삽입하면 다음 중 한 시점에서 IMessage를 처리할 수 있습니다.

  • 메시지로 나타낸 호출을 스트림으로 변환하여 유선으로 보내는 프로세스 도중

  • 유선으로 스트림을 받아 서버의 원격 개체 앞에 있는 마지막 메시지 싱크인 StackBuilderSink 개체나 클라이언트의 프록시 개체로 보내는 프로세스 도중

사용자 지정 싱크에서는 해당 호출이 나가는 호출인지 들어오는 호출인지 여부에 따라 스트림의 데이터를 읽거나 스트림에 데이터를 쓰고 필요한 경우 헤더에 정보를 추가할 수 있습니다. 이 단계에서 메시지는 포맷터에 의해 이미 serialize되어 있으며 수정할 수 없습니다. 메시지 호출이 체인의 끝에 있는 전송 싱크에 전달되면 전송 싱크에서는 스트림에 헤더를 쓰고 해당 채널에서 지정한 전송 프로토콜을 사용하여 스트림을 서버의 전송 싱크에 전달합니다.

전송 싱크

전송 싱크는 클라이언트측에서는 체인의 마지막 싱크이고 서버측에서는 체인의 첫 번째 싱크입니다. serialize된 메시지를 전송하는 것 외에도 전송 싱크에서는 서버에 헤더를 보내고 서버에서 호출이 반환될 때 헤더와 스트림을 검색합니다. 이러한 싱크는 채널에 빌드되며 확장할 수 없습니다.

기본 포맷터 대체

채널은 추상적인 네트워킹 메커니즘이므로 .NET Remoting 시스템에서 사용자가 선택한 포맷터와 시스템 구현 채널을 연결하도록 구성할 수 있습니다. 이 때 채널 속성의 IDictionary 구현, 서버측 포맷터 및 클라이언트측 포맷터를 받아들이는 채널 생성자를 사용할 수 있습니다. 구성 파일에서 포맷터를 지정할 수도 있습니다. 다음 예에서는 .NET Remoting 구성 시스템에서 HttpChannel을 만들지만 클라이언트측에서는 BinaryClientFormatterSink를 사용하도록 지시하는 방법을 보여 줍니다.

<configuration>
   <system.runtime.remoting>
      <application>
         <channels>
            <channel ref="http">
               <clientProviders>
                  <formatter ref="binary"/>
               </clientProviders>
         <channels>
      </application>
   </system.runtime.remoting>
</configuration> 

다음 코드에서는 동일한 작업을 프로그래밍 방식으로 수행합니다. 이 예에서는 GetServerStringGetServerTime을 구현하는 원격 인터페이스 형식 IService를 가정합니다.

Imports System
Imports System.Collections
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http

Public Class ClientProcess
  <MTAThread()> _
  Public Shared Sub Main()
      
    ' Note that any name/value pairs of configuration attributes can be 
    ' placed in this dictionary (the configuration system calls this same 
    ' constructor).
    Dim properties As New Hashtable()
    properties("name") = "HttpBinary"
     
    ChannelServices.RegisterChannel(New HttpChannel(properties, New BinaryClientFormatterSinkProvider(), Nothing))
    ' The last parameter above (Nothing) is the server sink provider chain 
    ' to obtain the default behavior (which includes SOAP and 
    ' binary formatters on the server side).
    Dim service As IService = CType(Activator.GetObject(GetType(IService), "http://computer:8080/SAService"), IService)
      
    Console.WriteLine("Server string is: " + service.GetServerString())
    Console.WriteLine("Server time is: " + service.GetServerTime())
  End Sub
   
End Class 
using System;
using System.Collections;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

public class ClientProcess{

  public static void Main(string[] Args){
        
    // Note that any name/value pairs of configuration attributes can be 
    // placed in this dictionary (the configuration system calls this 
    // same HttpChannel constructor).
    IDictionary properties = new Hashtable();
    properties["name"] = "HttpBinary";

    // The last parameter below is the server sink provider chain 
    // to obtain the default behavior (which includes SOAP and binary 
    // formatters) on the server side.
    ChannelServices.RegisterChannel(new HttpChannel(null, new BinaryClientFormatterSinkProvider(), null));

    IService service = (IService)Activator.GetObject(typeof(IService),"http://computer:8080/SAService");
        
    Console.WriteLine("Server string is: " + service.GetServerString());
    Console.WriteLine("Server time is: " + service.GetServerTime());      
  }
}

인터넷 정보 서비스에서 호스팅되는 이 채널 및 포맷터 조합에 대한 전체 예는 원격 서비스 예: IIS에서 호스팅을 참조하십시오.

이 클라이언트에서 TcpChannel 개체를 SoapClientFormatterSink 개체와 함께 사용하도록 변경하려면 다음 코드 예에서와 같이 해당 네임스페이스 및 RegisterChannel 호출만 변경해야 합니다.

ChannelServices.RegisterChannel(New TcpChannel(properties, New SoapClientFormatterSinkProvider(), Nothing))
ChannelServices.RegisterChannel(new TcpChannel(null, new SoapClientFormatterSinkProvider(), null));

참고 항목

개념

IIS에서 원격 개체 호스팅
원격 서비스 예: IIS에서 호스팅

기타 리소스

고급 원격 서비스