NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# 2부 - C# ZeroMQ를 이용한 발행과 구독. (Publish and Subscribe.)

    페이지 정보

    본문

    안녕하세요. 소심비형입니다. 오늘은 ZeroMQ를 이용하여 퍼블리싱이 가능한 시스템 또는 장치에서 보낸 메시지를 클라이언트가 수신하는 방법에 대해서 알아보도록 하겠습니다. 처음 의도는 1:1 채팅과 발행 및 구독을 이용해서 멀티 채팅까지 진행하려 했으나... 크게 의미가 있나 싶군요. [ 이전 글 ]과 이번 발행과 구독을 참조 하시면 충분히 스스로 만들 수 있을거라 생각합니다. 시간이 된다면 만들고 싶긴하지만^^;

    FaQOYct.gif

     

     

    좀 더 명확하게 시나리오를 특정하자면, 반도체를 생산하는 양산 장비에서 LOT이 투입되고 다음 공정으로 LOT이 나갈 때를 생각해 볼 수 있습니다. 많은 장비가 있을테지만 클라이언트는 특정 장비에만 관심이 있습니다. 그렇다면 관심이 있는 특정 장비에서 올라오는 이벤트만 구독하면 되겠죠. 이와 비슷한 시나리오와 솔루션은 이미 많이 소개가 되고 있습니다. 다른 메시지 관련 라이브러리에 관심이 있는 분들은 [ 여기 ]를 한번 읽어보세요. 분산 메시지 처리에 관련된 솔루션들의 간단한 소개입니다.

    bu22lrG.png

     

     

    진행하기에 앞서 Publisher와 Subscriber 콘솔 프로젝트를 추가합니다. 저는 Utilities폴더에 추가 했습니다. 2개로 나눈 이유는 복잡성을 덜기 위함입니다. 옵션을 설정해서 역할을 지정할 수도 있지만, 학습 차원에서 단순하게 만드는게 좋겠습니다.

    GIdECee.png

     

     

    추가한 2개의 프로그램은 모두 콘솔 프로그램입니다. 따라서 좀 더 편리하게 커멘드 라인을 제어하기 위해 CommandLineParser Library를 설치합니다. 그리고, 이전 글에서 설치한 ZeroMQ도 같이 설치 해줍니다. 만약, 같은 솔루션에 있는 프로젝트라면 packages폴더에 이미 설치되어 있을수도 있습니다. packages폴더에서 직접 참조를 추가해도 됩니다.

     

    Visual Studio의 패키지 관리자 콘솔에 아래 명령어를 통해 설치합니다.

    PM> Install-Package CommandLineParser

     

    참조에는 ①CommandLine과 ①ZeroMQ가 포함되어 있어야 합니다. 그리고 ②libsodium.dll과 ②libzmq.dll을 프로젝트에 추가시킵니다. 이 두 파일은 빌드할 때 같이 배포되어야 하므로, 출력 디렉토리로 복사 속성을 변경된 내용만 복사로 변경합니다. 마지막으로 ③Options 클래스도 추가합니다.

    blUdRBn.png

     

     

    발행자의 커멘드 옵션에 대한 처리를 담당할 클래스입니다. 설명은 각 속성의 Attribute에 있는 HelpText를 참고하세요. Window Command에서 -h를 통해 옵션들을 확인할 수 있습니다.

    Options.cs

    using CommandLine;
    using CommandLine.Text;
     
    namespace PublisherForZeroMQ
    {
        class Options
        {
            [Option('e', "EndPoint", Required = true, 
                HelpText = "EndPoint를 설정합니다.")]
            public string EndPoint
            {
                get; set;
            }
     
            [Option('m', "Message", Required = true, 
                HelpText = "메시지를 설정합니다.")]
            public string Message
            {
                get; set;
            }
     
            [Option('d', "Delay", Required = false, DefaultValue = 0, 
                HelpText = "메시지 전송에 필요한 지연 시간을 설정합니다. 기본값은 0입니다.")]
            public int Delay
            {
                get; set;
            }
     
            [ParserState]
            public IParserState LastParserState
            {
                get; set;
            }
     
            [HelpOption('h', "Help", 
                HelpText = "화면에 도움말을 표시합니다.")]
            public string GetUsage()
            {
                return HelpText.AutoBuild(this, (HelpText current) 
                    => HelpText.DefaultParsingErrorsHandler(this, current));
            }
        }
    }
    

     

     

    아래는 Publisher의 전체 코드입니다.

    Program.cs

    using System;
    using System.Text;
    using System.Threading;
    using ZeroMQ;
     
    namespace PublisherForZeroMQ
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    var options = new Options();
     
                    if (!CommandLine.Parser.Default.ParseArguments(args, options))
                        Environment.Exit(1);
     
                    using (var context = ZContext.Create())
                    using (var socket = new ZSocket(context, ZSocketType.PUB))
                    {
                        socket.Bind(string.Format("tcp://{0}", options.EndPoint));
     
                        while (true)
                        {
                            Thread.Sleep(options.Delay);
                            socket.Send(new ZFrame(options.Message, Encoding.UTF8));
                            Console.WriteLine("Publishing: {0}", options.Message);
                            options.Message = Console.ReadLine();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }

     

     

    Subscriber도 Publisher와 똑같이 설정합니다. 아래는 Subscriber의 Options입니다.

    Options.cs

    using CommandLine;
    using CommandLine.Text;
     
    namespace SubscriberForZeroMQ
    {
        class Options
        {
            [Option('e', "EndPoint", Required = true, 
                HelpText = "EndPoint를 설정합니다.")]
            public string EndPoint
            {
                get; set;
            }
     
            [Option('s', "Prefix", Required = false, 
                HelpText = "메시지를 필터링하기 위한 접두사를 설정합니다.")]
            public string SubscriptionPrefix
            {
                get; set;
            }
     
            [Option('d', "Delay", Required = false, DefaultValue = 0, 
                HelpText = "메시지 전송에 필요한 지연 시간을 설정합니다. 기본값은 0입니다.")]
            public int Delay
            {
                get; set;
            }
     
            [ParserState]
            public IParserState LastParserState
            {
                get; set;
            }
     
            [HelpOption('h', "Help", 
                HelpText = "화면에 도움말을 표시합니다.")]
            public string GetUsage()
            {
                return HelpText.AutoBuild(this, (HelpText current) 
                    => HelpText.DefaultParsingErrorsHandler(this, current));
            }
        }
    }

     

     

    아래는 Subscriber의 전체 소스입니다.

    Program.cs

    using System;
    using System.Text;
    using System.Threading;
    using ZeroMQ;
     
    namespace SubscriberForZeroMQ
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    var options = new Options();
     
                    if (!CommandLine.Parser.Default.ParseArguments(args, options))
                        Environment.Exit(1);
     
                    using (var context = ZContext.Create())
                    using (var socket = new ZSocket(context, ZSocketType.SUB))
                    {
                        if (string.IsNullOrEmpty(options.SubscriptionPrefix))
                            socket.SubscribeAll();
                        else
                            socket.Subscribe(options.SubscriptionPrefix);
     
                        socket.Connect(string.Format("tcp://{0}", options.EndPoint));
                        Console.WriteLine("Start Subscriber: {0}", 
                            string.IsNullOrEmpty(options.SubscriptionPrefix) ? "ALL" : options.SubscriptionPrefix);
     
                        while (true)
                        {
                            Thread.Sleep(options.Delay);
                            var msg = socket.ReceiveFrame();
                            Console.WriteLine("Received: " + msg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
    

     

     

    모든 기능을 개발했으므로, 이제 테스트를 Command에서 진행해야 합니다. Window key + R(실행) > cmd 를 실행시키고 아래와 같이 Subscriber가 빌드된 폴더로 이동합니다. cd 명령을 이용하여 해당 폴더로 이동한 후 아래 명령을 실행하세요.

    start "Subscriber PHOTO" SubscriberForZeroMQ -e "127.0.0.1:2000" -s "PHOTO" -d 0

    u7e5php.png

     

     

    포토 장비의 메시지를 받기 위한 구독자(Subscriber)가 실행되고, 메시지를 받기 위한 수신 상태가 됩니다.

    2aqOsim.png

     

     

    아래와 같이 CVD장비와 모든 장비 메시지를 구독할 Subscriber를 실행 시킵니다.

    oW3PhYx.png

     

     

    PHOTO, CVD와 모든 장비 메시지를 구독할 Subscriber가 실행되고 있습니다.

    TQ0bBmR.png

     

     

    이제 Publisher를 실행하고 각 장비에서 올라오는 메시지를 발행합니다. 퍼블리셔는 메시지를 발행하고 입력 상태로 유지됩니다. 접두사(Prefix)와 함께 보내고 싶은 메시지를 입력하면 접두사가 Subscriber로 설정된 장비가 메시지를 수신하게 됩니다. 마지막에 있는 "ALL"은 접두사를 지정하지 않았으므로 모든 메시지를 받게 됩니다.

    jUgDBv1.png

     

     

    장비에서 TCP를 통해 메시지가 올라오면 Publisher가 발행하고, Subscriber는 관심있는 장비의 메시지만을 받아서 처리할 수 있습니다. 참고로, 각 콘솔 프로그램의 설명을 보려면 -h를 통해 확인할 수 있습니다.

    IWYfIWt.png

     

     

    이렇게 2회에 걸쳐 아주 심플하게 zeromq를 이용한 메시지 처리에 대해서 알아봤습니다. 가난한(?) 제조 업체에서는 주로 activemq를 사용해서 적용 했기에 시간이 될 때 activemq에 대해서도 알아보면 좋겠군요. 레거시쪽 프로젝트를 하다가 우연히 볼지도 모르니까요^^;

    7wHj4Bu.png

     

     

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.