.NET 리모팅

안녕하세요. 언제나 휴일에 언휴예요.
이번에는 닷넷 리모팅 기술을 이용한 간단한 클라이언트와 서버를 제작하는 실습이예요.

1. .NET 리모팅이란?

.NET 리모팅 기술은 서버 측에 있는 개체를 클라이언트 측에서 마치 자신에게 있는 개체를 사용하는 것처럼 사용할 수 있게 서비스를 하는 기술입니다.

.NET 리모팅 서비스를 위해서는 서비스를 제공하는 서버와 서비스를 제공받는 클라이언트가 필요하며 서버 측에서 클라이언트에 제공하는 개체를 정의한 클래스 라이브러리가 필요합니다.

서버 측에서 클라이언트에 제공하는 개체는 MashalByReference에서 파생한 개체로 원격 개체라고 말합니다.

서버 측에서는 채널을 등록하여 원격 개체를 사용할 수 있게 등록합니다. 클라이언트 측에서는 서버 측 채널에 접근하여 원격 개체를 참조하여 사용하는데 클라이언트 측에서 원격 개체를 참조하여 사용할 수 있는 개체를 Proxy 개체라 부릅니다.

클라이언트 측에서 Proxy 개체를 통해 메서드를 호출하면 포멧터를 통해 메서드 이름과 인자 등을 Masharing하여 서버 측에 전달하면 서버 측의 Stub에서 이를 수신하여 실제 개체인 원격 개체를 제어합니다. 그리고 결과를 같은 방법으로 서버 측의 Stub에서 클라이언트 측의 Proxy 개체에게 전송하고 Proxy개체는 수신한 정보로 결과를 반환하는 원리입니다.

.NET 리모팅 구조
[그림 ] .NET 리모팅 구조

간단하게 .NET 리모팅 서비스를 구축하고 이를 사용하는 클라이언트를 구현해 봅시다.

여기에서 실습할 내용은 숫자를 문자열로 변환하는 서비스입니다.

2. .NET 리모팅에서 제공할 라이브러리 제작

.NET 리모팅에서 제공할 라이브러리에는 MashalByRefObject에서 파생한 클래스를 정의해야 합니다.

이 외에는 일반적인 라이브러리 제작과 차이가 없습니다.

using System;

namespace GeneralLib
{
    public class General:MarshalByRefObject
    {
        public string ConverIntToStr(int num)
        {
            Console.WriteLine("ConvertIntToStr 메소드 수행(전달 받은 인자:{0})", num);
            switch(num)
            {
                case 0: return "영";
                case 1: return "일";
                case 2: return "이";
                default: return "아직 모르는 수예요.";
            }
        }
    }
}

3. .NET 리모팅 서버 제작

여기에서는 콘솔 응용 프로그램 형태로 제작할게요.
.NET 리모팅 서버를 구축하려면 System.Runtime.Remoting 어셈블리를 참조 추가해야 합니다.
그리고 앞에서 만든 라이브러리를 참조 추가하세요.

서버 측에서는 클라이언트에서 연결할 수 있는 채널을 등록합니다.
TCP 채널과 HTTP 채널을 사용할 수 있는데 여기에서는 방화벽에 친숙한 HTTP 채널을 생성하여 등록할게요.

그리고 클라이언트에서 원격으로 참조할 수 있는 개체 형식을 등록합니다. 등록할 수 있는 서비스 종류는 여러 가지가 있는데 여기에서는 서버 측 활성화 개체로 단일개체 모드로 등록할게요.

프로세스가 키를 누를 때까지 종료하지 않고 대기할 수 있게 합시다.

using GeneralLib;
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace 리모팅_서버
{
    class Program
    {
        static void Main(string[] args)
        {
            HttpChannel hc = new HttpChannel(10400);//TCP :BinaryFormatter, HTTP:SoapFormatter
            ChannelServices.RegisterChannel(hc, false);
            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(General),
                "MyRemote",
                WellKnownObjectMode.Singleton);
            Console.ReadKey();
        }
    }
}

서버 제작이 끝났습니다.

4. 클라이언트 제작

클라이언트도 앞에서 만든 라이브러리를 참조 추가합니다.

System.Runtime.Remoting 어셈블리도 참조 추가합니다.

채널을 생성하고 등록합니다.

그리고 Activator의 정적 메서드 GetObject를 통해 서버 채널에서 서비스 개체를 참조합니다.

여기에서 참조하는 개체를 Proxy 개체라고 부릅니다.

클라이언트에서 Proxy 개체에게 명령을 내리면 내부적으로 서버 측에 있는 Stub에게 전달하며 Stub은 서버 측의 원격 개체에게 명령을 내리고 결과를 Proxy에게 전달합니다.

개발자는 단지 Proxy 개체를 편하게 사용하기만 하면 내부적으로 알아서 해 줍니다.

using GeneralLib;
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace 리모팅_클라이언트
{
    class Program
    {
        static void Main(string[] args)
        {
            HttpChannel hc = new HttpChannel();
            ChannelServices.RegisterChannel(hc, false);
            General gen = Activator.GetObject(
                typeof(General),
                "http://[서버의 IP 주소]:10400/MyRemote"
                ) as General;
            string str = gen.ConverIntToStr(2);
            Console.WriteLine("호출 결과:{0}", str);
            Console.ReadLine();
            str = gen.ConverIntToStr(1);
            Console.WriteLine("호출 결과:{0}", str);
            Console.ReadLine();
            str = gen.ConverIntToStr(3);
            Console.WriteLine("호출 결과:{0}", str);
            Console.ReadLine();
            str = gen.ConverIntToStr(0);
            Console.WriteLine("호출 결과:{0}", str);
            Console.ReadLine();
        }
    }
}

서버와 클라이언트를 실행하여 테스트 해 보세요.

서버 실행 결과

ConvertIntToStr 메소드 수행(전달 받은 인자:2)
ConvertIntToStr 메소드 수행(전달 받은 인자:1)
ConvertIntToStr 메소드 수행(전달 받은 인자:3)
ConvertIntToStr 메소드 수행(전달 받은 인자:0)

클라이언트 실행 결과

호출 결과:이
호출 결과:일
호출 결과:아직 모르는 수예요.
호출 결과:영