NamedPipe

최용국·2020년 5월 9일
0

기타

목록 보기
2/6
post-thumbnail

NamedPipe

서로 다른 프로세스끼리 메시지나 데이터를 주고 받고싶을 때가 있을 것이다. 프로세스 통신에는 여러가지 방법들이 있는데 그 중 NamedPipe 명명된 파이프를 통해 통신하는 방법을 알아봅니다. Pipe의 특징으로는 단방향 통신이다 라는 것만 알고 넘어가면 코드는 아주 간단합니다.

예제로는 서로 다른 프로젝트 NamedPipeProject1(Server), NamedPipeProject2(Client)가 있고 자체 라이브러리인 StudyNamedPipe 인스턴스를 생성해 NamedPipeProject2에서 보낸 메시지를 NamedPipeProject1 Console에 출력합니다.

StudyLibrary

class StudyLibrary

public class StudyNamedPipe : IDisposable
{
    public const int BufferSize = 4096;

    public delegate void DelegateRead(string message);
    public event DelegateRead ReadEvent;
    public delegate void DelegateConnected();
    public event DelegateConnected ConnectedEvent;
    public delegate void DelegateDisConnected();
    public event DelegateDisConnected DisConnectedEvent;
    public bool IsDisposed
    {
        get;
        private set;
    } = false;

    public bool AlreadyOpen 
    { 
        get; 
        private set; 
    } = false;

    public string Name
    {
        get;
        private set;
    }

    public StudyNamedPipe(string name)
    {
        Name = name;
    }

    public NamedPipeServerStream ServerStream { get; private set; }
    public NamedPipeClientStream ClientStream { get; private set; }
    public void ClientOpen()
    {
        if (AliveCheck())
            return;

        ClientStream = new NamedPipeClientStream(this.Name);

        ClientStream.Connect();
        AlreadyOpen = true;
    }

    public void Write(string message)
    {
        if (!AliveCheck())
            return;

        var msgBytes = Encoding.UTF8.GetBytes(message);
        ClientStream.Write(msgBytes, 0, (int)msgBytes.Length);
        ClientStream.Flush();
    }

    private bool AliveCheck()
    {
        /// TODO
        /// throw exception
        if (IsDisposed)
            throw new Exception();

        /// TODO
        /// throw exception
        if (AlreadyOpen)
            return true;

        return false;
    }

    public async void ServerOpen()
    {
        if (AliveCheck())
            return;

        ServerStream = new NamedPipeServerStream(this.Name);
        AlreadyOpen = true;

        await ServerStream.WaitForConnectionAsync();
        ConnectedEvent?.Invoke();

        while(ServerStream.IsConnected)
        {
            var readBytes = new byte[BufferSize];
            await ServerStream.ReadAsync(readBytes, 0, (int)readBytes.Length);
            
            var message = Encoding.UTF8.GetString(readBytes);
            ReadEvent?.Invoke(message.TrimEnd((char)0));
        }

        DisConnectedEvent?.Invoke();
        this.Dispose(true);
    }

    ~StudyNamedPipe()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    public void Dispose(bool dispose)
    {
        if (IsDisposed)
            return;

        if(dispose)
        {
            AlreadyOpen = false;
        }

        ServerStream?.Dispose();
        ClientStream?.Dispose();

        IsDisposed = true;
    }
}

NamedPipeProject1

Program

class Program
{
    static void Main(string[] args)
    {
        StudyNamedPipe studyNamedPipe = new StudyNamedPipe("123");
        studyNamedPipe.ReadEvent += StudyNamedPipe_ReadEvent;
        studyNamedPipe.ConnectedEvent += StudyNamedPipe_ConnectEvent;
        studyNamedPipe.DisConnectedEvent += StudyNamedPipe_DisConnectedEvent;
        studyNamedPipe.ServerOpen();

        while (true)
        {
            Console.ReadLine();
        }
    }

    private static void StudyNamedPipe_DisConnectedEvent()
    {
        Console.WriteLine("Pipe가 연결이 끊겼습니다.");
    }

    private static void StudyNamedPipe_ConnectEvent()
    {
        Console.WriteLine("Pipe가 연결되었습니다.");
    }

    private static void StudyNamedPipe_ReadEvent(string message)
    {
        Console.WriteLine(message);
    }
}

NamedPipeProject2

Program

class Program
{
    static void Main(string[] args)
    {
        StudyNamedPipe studyNamedPipe = new StudyNamedPipe("123");
        studyNamedPipe.ClientOpen();

        while (true)
        {
            var input = Console.ReadLine();
            studyNamedPipe.Write(input);
        }
    }
}

결과

Server & Client

Server

소스 위치
github: https://github.com/opzerg/YGStudy.git
solution: Others
project NamedPipeProject1
project NamedPipeProject2
project StudyLibrary

profile
코딩합시다.

0개의 댓글