반응형

C# : using문의 기능과 활용

알게 된 배경

 C++에서 개발을 하다가 C#을 접하게 되었을 때 익숙하면서도 생소한 문법이 using문이었다. C++에서도 namespace를 선언할 경우 'using namespace [이름];' 형태의 문법을 사용하고 C#에서도 마찬가지로 최상단에 'using System;' 형태로 기본적으로 작성이 되어 있기 때문이다.


 하지만, 입문을 제대로 하지 않은 상태에서 파일, 네트워크 등 IO(입출력)에 해당되는 MSDN 문서를 보면 코드의 메서드 안에서 사용되는 using문을 쉽게 볼 수 있다. 하지만, 기존에 using 사용되던 키워드(?)와 다른 기능이라서 처음에 쉽게 사용하기 어렵다.


 특히나 예외처리 문법의 finally 문의 기능과 유사했기 때문에 필자의 경우 예제를 보기 전까지는 제대로 활용을 하지 못 했었다.


using문의 의미

 키보드와 콘솔 화면 출력을 제외한 대부분의 IO(입출력)의 경우 실제로 stream이나 unmanagement 메모리 공간을 할당하고 해제 하는 패턴 혹은 Stream Open 과 Stream Close 하는 패턴으로 코드를 작성해야 한다.


 C++의 경우 소멸자가 유용하게 사용되는데, C# 역시 소멸자를 제공하지만, IDisposeable 인터패이스를 상속하여 Dispose라는 메서드를 override하여 Unmanagement 메모리 해제나 Stream Close를 구현하도록 권장을 하고 있다. 그리고 이렇게 구현된 Dispose 메서드는 using문의 Scope에서 벗어나면, 호출이 하도록 하여 자연스럽게 C++의 소멸자와 비슷한 기능을 수행한다.


using문 예시


using System;
using System.IO;

class FileRead
{
    var imgFilePath = @".\img.jpg";
    using(var imgFileStream = new FileStream(imgFilePath, FileMode.Open))
    {
        var tmpImg = Image.FromStream(imgFileStream);
        // ... 중략
    }
}



예외처리의 finally문과의 관계

 IO처리에 있어서 항상 염두해야 하는 문법은 예외 처리이다. 이는 파일 입출력의 경우 파일을 읽을 때 파일이 없는 경우, 통신중에 네트워크 연결이 끊어진 경우 등 비정상적인 동작을 대비해서 작성하는 문법이다.


 여기서 finally 문의 경우 예외가 발생하던 안하던 간에 반드시 실행되는 내용을 작성을 하도록 되어 있다. 가령 Stream Open 한뒤에 작업중에 예외가 발생해서 파일을 닫아야 하지만, 예외 발생 하지 않은 경우에도 닫아야 하는 경우에 사용된다.


try-catch-finally문 예시

using System;
using System.IO;

class FileRead
{
    var imgFilePath = @".\img.jpg";
    try
    {
        var imgFileStream = new FileStream(imgFilePath, FileMode.Open);
        var tmpImg = Image.FromStream(imgFileStream);
        // ... 중략
    }
    catch(Exception ex)
    {
        // ... 예외 처리
    }
    finally
    {
        imgFileStream.Close();
        // ... 혹은 imgFileStream.Dispose() 호출
    }
}




 여기서 생각을 가만히 해보면 finally문이 using문과 역할의 유사점을 느낄 수 있다. 오히려 finally문의 경우 Close 같은 메서드를 직접 호출하는 반면, using문은 IDisposeable을 상속 받은 객체의 경우 자동으로 Scope를 벗어나면 Dispose() 메서드를 호출한다.


 그리고 MS의 대부분 Stream에 관련된 클래스들은 Dispose() 메서드에 이러한 기능들이 정의 되어 있다. 따라서 IO 구현시 가능하면 using문을 사용하는 것이 실수를 예방하기에 좋은 편이다.



using문/try-catch 패턴 예시


using System;
using System.IO;

class FileRead
{
    var imgFilePath = @".\img.jpg";
    using(var imgFileStream = new FileStream(imgFilePath, FileMode.Open))
    {
        try
        {
            var tmpImg = Image.FromStream(imgFileStream);
            // ... 중략
        }
        catch(Exception ex)
        {
            // ... 예외 처리
        }
    }
}


 위의 패턴으로만 보았을 때 using문-try-catch 패턴이 깔끔해보인다. 하지만, 처음 using문에서 사용할 객체를 만드는 순간에 발생하는 예외의 경우 처리가 안되는 패턴이기 때문에 이를 피하기 위해서 파일 존재 여부 검사와 같은 추가 코드가 필요하다.



참고자료

도서: C# 7과 닷넷 코어 2.0


반응형

'C#' 카테고리의 다른 글

C# .NET: Dispose (소멸자) 패턴  (0) 2018.05.14
C# .NET : SQLLocalDB (1) 개요와 오류사례  (0) 2018.03.23
C# : this와 base  (0) 2018.02.20
C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
반응형

C# .NET: Dispose (소멸자) 패턴

알게된 배경

 클래스가 프로그래밍 언어에서 등장할 때 가장 먼저 배우는 것이 생성자이다. 이후 생성자의 반대 개념인 소멸자(혹은 파괴자, 제거자 등 여러 이름으로 부를 수 있는 개념)개념이다.

 이는 기존 C++ 같은 언어에서 힙(요즘에는 이 힙을 자유공간(Free Space)라고 부르자고 제안되고 있음)에 할당된 메모리를 관리(할당과 해제)를하기 위해서였다.


 그러나 시간이 지나고 나서 GC(Garbage Collection)가 등장하고 나서 부터는 소멸자의 존재 의미가 애매 해졌다. C# DotNet Core 에서부터는 소멸자가 사라지게 되었지만, 기존의 DotNet FrameWork의 경우 아직도 소멸자가 건재하다.


 DotNet FrameWork에서는 메모리 관리 방법이 Management와 Unmanagement로 2가지 방법이 있다. Management는 말그대로 CLR이 관리를 해준다(이는 GC의 동작도 포함). 반면, Unmanagement는 CLR이 관여를 하지 않는다. 이렇게 Unmanagement한 영역은 Stream을 사용하는 부분과 소켓 프로그래밍을 위한 버퍼 등이 포함된다. 이러한 영역은 개발자가 직접 해제하는 코드를 작성해줘야 하는데, 이럴때 사용되는 것이 소멸자였다.


 그러나 DotNet FrameWork에서는 Dispose라는 인터페이스를 제공을 해주고 있는데, 이 인터페이스는 GC가 해당 Class의 인스턴스를 제거할 때 해당 작업을 먼저 하도록 되어 있다. 문제는 앞에서 언급된 Dispose 인터페이스와 소멸자의 역할이 유사하다 보니 오작동 될 가능성이 있다. 때문에 이러한 패턴이 생겨나게 되었다.


 Dispose 메서드는 IDisposeable 인터페이스를 상속 받아서 구현하면, using() 으로 호출하면 해당 스코프(혹은 스택)을 벗어나면, 호출이 된다.



패턴 예제



using System.Net.Sockets;

class UdpListenClass : IDisposeable
{
    private UdpClient Listener { get; private set; }
    // .. 중략
    // Start Destroyer Pattern
    private bool _disposed = false;
    private void Dispose(bool calledDestroyer)
    {
        if(false == _disposed)
        {
            // 소켓을 닫거나 Unmamagement 메모리를 여기서 해제하면 된다
            Listener.Close();
            _disposed = true;
        }
        if(false == calledDestroyer)
        {
            GC.SuppressFinalize(this);
        }
    }
    public void Dispose()
    {
        Dispose(false);
    }
    ~UdpSocket()
    {
        Dispose(true);
    }
    // End Destroyer Pattern
    // ... 중략
}


 혹시나 오해가 될까 추가로 적자면, 소멸자는 ~[클래스명]으로 선언 정의 된다. Dispose는 소멸자가 아니지만, using문 패턴에서 호출되는 인터패이스다. 그리고 최근에 나오고 있는 DotNet Core에서는 소멸자를 더 이상 사용하지 않는다.


 물론 DotNet FrameWork랑 독립적으로 업데이트가 되고 있지만, 새로운 기능을 2017년 8월부터 DotNet Core에 먼저 추가가 되고 이후에 DotNet FrameWork에 추가 할 것이라고 MS에서 발표를 했으니 참조만 하자


참고 자료

도서: 시작하세요. C# 6.0

도서: C# 7과 닷넷 코어 2.0

반응형

'C#' 카테고리의 다른 글

C# : using문의 기능과 활용  (0) 2018.05.15
C# .NET : SQLLocalDB (1) 개요와 오류사례  (0) 2018.03.23
C# : this와 base  (0) 2018.02.20
C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
반응형

C# .NET : SQLLocalDB

배경

 인터넷 네트워크는 아니지만, 응용프로그램에서 내부적인 DB를 저장하고 사용해야 하는 경우가 종종 있다. 이 경우 DB의 비중은 비교적 낮기 때문에 DBMS의 크기가 작으며, 많은 기능이 필요로 하지않는다.

 최근 임베이디드 환경의 프로젝트를 진행을 하고 있다. 임베이디드 같이 근거리 통신에 디바이스간 통신에 대해서 다룰 경우에는 이 처럼 작은 DBMS가 더 적합하다.



SQLLocalDB 설치 방법

 간단하게 말하면 SQL Server를 설치하면 된다.


 MS SQL Server 2008 부터 express 버전에서부터 사용할 수 있게 해 놓았다(혹시 필자가 잘못 알고 있다면, 알려 주기 바람). 이 글을 기록하는 시기에서는 MS SQL Server 2017 Express 버전을 설치하면, 무료로 사용이 가능하다.


 다만, 설치가 옵션으로 설치되는 것이라서 설치과정중 구성요소에서 설치 체크를 해야한다.


 SQL Server 2017이 리눅스와 OS X 등에서 크로스 플랫폼으로 사용이 가능하다고 홍보를 하고 있지만, exe 파일로 제공되니 차후 재 빌드 파일이 나오지 않는다면, DOTNET Core로 실행해야 할 가능성이 있다.


 설치가 정상적으로 이루어지면, Visual Studio 2017 등 에서 바로 사용이 가능하다.



SQLLocalDB의 호환성

 당연한 이야기이지만, SQL Server와 달리 닷넷 환경에서 사용이 가능하고 현재로써는 Windows 에 국한이 되어 있다. 그리고 우리가 모르는 사이에 Windows에서 이미 SQLLocalDB를 사용하고 있다. 때문에 배포 환경이 Window 10 이라면, 웬만하면 따로 프로그램을 설치 하지 않아도 사용이 가능하다.


 여기 까지는 MS사의 설명이지만, 실제로는 배포하는 프로그램의 경우 가능 하면 사용을 자제하는 것이 좋다. 이유는 배포 환경에 대해서 완전한 독립성을 보장을 해주지 않는다. 이는 다시 말하자면, 어떤 PC에서는 정상적으로 DB인스턴스가 생성되어 사용이 가능하지만, 어떤 PC에서는 적절한 DB인스턴스가 생성되지 않는다.


 이를 해결하기 위해서는 MS Sql Server 를 설치해야 하는데, 배포하는 프로그램에서 갑자기 Sql Server를 설치하라고 하는 것은 다소 무리가 있다. 연습용으로만 사용하자.



필수도구

 쉽게 관리하기 위한 툴로 SSMS(SQL Server Management Studio)을 사용할 수 있다. 초기 시작할때 "(LocalDB)\MSSQLLocalDB" 로 접속을 하면, PC에 있는 mdf 확장자를 가진 데이터베이스를 확인할 수 있다. 수정에는 제약이 있지만(아마도 Express 버전이라서), 대부분의 내용을 확인이 가능하다.


 "sqllocaldb.exe"라고 하는 유틸리티가 대부분 기본적으로 Windows에 설치되어 있다. 못 믿겠다면, 당장 powershell 이나 cmd 에서 명령어를 사용하면, 도움말 정보를 띄우는 것을 확인 할 수 있다. 이 유틸리티를 통해서 응용프로그램에서 사용하는 mdf 파일에 접근하는데 필요한 디비 인스턴스를 관리 할 수 있다.



오류 사례

다른 PC에서 Access 거부

 개발 PC가 아닌 다른 PC에서 mdf 파일에 접근이 안되는 경우가 있다. 필자도 이 문제로 많은 시간을 버렸다. 일단 필자의 경우 sqllocaldb.exe 를 통해서 확인 해본 결과 실행이 안되는 PC에서 생성된 "MSSQLLocalDB" 인스턴스 버전은 v13.0 으로 생성된것에 반해 개발 PC에서는 v14.0 으로 생성이 되었었다. 그리고 개발 PC에서만 실행이 되었다.


 하지만, 자택에 있는 다른 PC에서 같은 소스코드로 mdf 만 새로 생성해서 다시 개발환경이 아닌 PC에서 실행을 해본 결과 실행이 잘되었다(역시 sqllocaldb.exe 로 "MSSQLLocalDB" 인스턴스 정보를 확인해보니 v13.01.. 으로 생성된 것을 확인 할 수 있었다).


(상단이 초기 개발 PC, 하단이 자택 PC)



 필자의 기억에 의하면, 먼저 잘 안된 PC 환경에서는 Visual Studio 2017 installer 에서 sql server 관련 패키지를 설치한 것 외에는 차이가 없었다. 앞으로는 개선이 되겠지만, 배포를 위해서라도 sql 관련 패키지를 visual studio 2017 installer 로 설치하는 것은 자제하자.



Git에서 mdf파일의 커밋제외

 그리고 git 을 사용할 경우 gitignore 파일 목록중에 mdf 확장자는 커밋에서 제외가 되니 이부분을 주의 해야한다. visual studio의 솔루션 창에는 보이지만 실제로는 존재하지 않는 파일이 되어 버린다.



참고자료




반응형

'C#' 카테고리의 다른 글

C# : using문의 기능과 활용  (0) 2018.05.15
C# .NET: Dispose (소멸자) 패턴  (0) 2018.05.14
C# : this와 base  (0) 2018.02.20
C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
반응형

C# : this와 base

정리배경

 무래도 C++을 사용하다가 C#을 접하게 되었기 때문에 유사한 키워드가 많아서 간과 하게 되는 부분들이 많다. 특히 this의 경우 친숙한 키위드이기 때문에 처음 공부를 할 때 스킵을 했다가 간단하면서 유용한 추가 기능이 있다는 것을 나중에 알게 되었다. base는 Java의 super와 같은 개념이나 이 역시 친숙한 기능은 아니였다.


 이러한 키워드들은 자주 사용하기 때문에 잊을 리는 없지만 정리 차원에서 작성해 놓는다.



this 키워드

 정의 된 클래스 내의 맴버(member)를 가르킬때 사용이 된다. 이러한 역할은 기존의 C++의 this와 동일한 기능이다.

 덤으로 코드 스타일은 프로젝트를 진행하는 팀별로 차이가 있지만, 맴버 객체 이름을 정할때 언더바("_")을 붙이거나 소문자 엠(m)을 붙이는 경우들이 있다.


예시1

class Book
{
    decimal isbn;
    public Book(decimal isbn)
    {
        this.isbn = isbn;
    }
}




 다른 기능은 클래스 내의 생성자에서 다른 생성자를 호출할때 사용된다. 일반적으로 생성자의 스코프(Scope)안에서 다른 생성자 호출을 되지 않지만, 생성자명 정의 직후 스코프전에 this 키워드를 사용하여 동일한 클래스내의 생성자를 호출하여 입력값을 전달하는게 가능해진다.


예시2

class Book
{
    decimal isbn;
    string title;
    string author;

    public Book(decimal isbn, string title)
        : this(isbn, title, string.Empty)
    {
    }

    public Book(decimal isbn, string title, string author)
    {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
    }

}




base 키워드

 Java의 super와 같은 키워드로 상속시 부모생성자에 입력값을 전달해야 할 경우 사용이 가능하다.


예시3

// 부모(parent)
class Book
{
    decimal isbn;
    public Book(decimal isbn)
    {
        this.isbn = isbn;
    }
}

// 자식(child)
class EBook : Book
{
    public EBook(decimal isbn)
        : base(isbn)
    {
    }
}




 C#의 base는 생성자 뿐만아니라 부모의 메서드를 호출 할 경우에도 사용이 가능하다. 이러한 기능은 후에 winform 등 override하여 기존 기능을 유지하면서 확장해야 할 경우에도 사용한다.

예시4

// 부모(parent)
public class Computer
{
    bool powerOn;
    public void Boot()
    {
        powerOn = true;
    }
}

// 자식(child)
public class Notebook : Computer
{
    public void ScanFinger()
    {
        base.Boot();
    }
}




참조자료

시작하세요 C#프로그래밍(서적)

반응형
반응형

C# Winform : Detect Resize (크기 변화 감지)

알게된 배경

 운영체제 별로 화면의 화소 사이즈가 다르며, 또 사용자에 따라서 편한 크기가 있다. 이 때문에 동적으로 크기를 바꿔줘야 한다. 때문에 창의 크기가 편할때 이를 감지를 하는 것은 제품을 만들기 위해서 중요한 문제일 수 있다.


 물론 이쁘고 동적인 UI를 만든다면, 가능하면, WPF를 쓰는 방법도 현명한 선택이 될 수 있다.



소스코드

 참조한 문서에 의하면, 별로 안어렵다고 한다. 기존에 크기 변화를 감지하는 메서드를 override를 하여서 추가 시킬 수 있다. 아래의 소스코드는 생성된 초기 디자인에서 코드보기를 한뒤에 작성하였다.


// Proect name = TestResize
using System;
using System.Windows.Forms;
namespace TestResize
{
    public partial class Form1 : Form
    {
        public ResizeForm()
        {
            InitializeComponent();
            mLastState = this.WindowState;
        }

        private FormWindowState mLastState;

        protected override void OnClientSizeChanged(EventArgs e)
        {
            // 폼의 크기가 바뀔때마다 인식
            if (this.WindowState != mLastState)
            {
                // 최대, 최소, 보통 등 상태가 변할때 마다 실행됨
                mLastState = this.WindowState;
                OnWindowStateChanged(e);
            }
            else
            {
                Console.WriteLine("Detect resize: {0}, {1}", Size.Width, Size.Height);
            }
            base.OnClientSizeChanged(e);
        }

        protected void OnWindowStateChanged(EventArgs e)
        {
            Console.WriteLine("Window State: {0}", WindowState);
        }
    }
}



빌드로 실행하기 전에 프로젝트 속성의 옵션 항목중에 "응용 프로그램" --> "출력형식" --> "콘솔 응용프로그램"으로 해야 콘솔창을 통해 코드가 작동이 되는지 확인할 수 있다.



참조자료

MSDN 포럼(영문)



반응형

'C#' 카테고리의 다른 글

C# .NET : SQLLocalDB (1) 개요와 오류사례  (0) 2018.03.23
C# : this와 base  (0) 2018.02.20
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
C# : 닷넷에서 Broadcast UDP를 보내기(1)  (0) 2018.01.29
C# : const vs readonly  (0) 2017.10.25
반응형

C# : Queue VS ConcurrentQueue

알게된 배경

UDP통신을 수신해야 하는데, 스레드 하나로는 프로그램의 성능을 올릴 수 없으니 당연히 멀티 스레드로 처리를 해야한다. (이는 UDP 프로토콜은 오버플러워되거나 에러가 난 패킷은 가차없이 폐기 처분하기 때문에 발생되는 문제를 막기 위함이다.) 문제는 이런 스레드가 작동되는 영역들간에 데이터 공유혹은 전달 할 수 있는 자료가 필요로 하게 된다. 이를 사용할 자료구조가 Queue였다.

 물론 링크리스트로도 충분히 구현을 할 수 도 있다.


큐의 개요

 많이 비교되는 자료구조는 스택이다. 스택은 먼저들어간게 나중에 나오는 구조(FILO or LIFO)인데 반해 큐는 들어간 순서대로 나오는 실제 세게에서 줄 서 있는 것과 같다. 추상적으로 생각을 하면, 우리가 일상중 머릿속에서 작업스케줄을 짜는 것과 같다.

 위의 예시처럼 실제로도 큐는 작업 스케줄 처럼 많이 사용되기도 한다. 큐의 종류는 선 큐, 환 큐, 링크드 큐로 분류가 되는데, 선 큐의 경우 오버플러워의 위험이 크기 때문에 잘 사용되지 않는다. 닷넷 한정으로 넣는 것을 Enqueue, 빼는 것을 Dequeue로 구현이 되어 있다.


닷넷 Queue 구조

 닷넷에서 제공하는 큐(Queue)는 환 큐에 속한다. 또한 성능을 향상시키기 위해서 정적 배열을 기반으로 하고 있다.

문제점

Queue가 비어 있을 경우 Dequeue를 시도하면 예외를 발생시킨다. 그래서 일반적으로 큐를 사용할 때 Count를 검사해서 0 이상일 때 Dequeue 사용하도록 구현을 한다. 다만, 설계시 멀티스레드에 대해서 생각을 못 한 것인지 다수의 스레드의 동시 접근시 문제가 발생된다. 때문에 Enqueue와 Dequeue에 크리티컬 섹션으로 설정해야 한다(lock을 구현해야함).

 이론상 2개의 스레드중 하나는 Enqueue만하고 다른 하나는 Dequeue만 하면, 문제가 없을 것 같지만, count등 내부적으로 공유되는 값으로 인해 간헐적인 값의 오류가 발생한다. 이러한 오류는 에러를 잘 발생시키지는 않지만, 의도한것과 다른 값을 결과로 내기 때문에 위험하다.

Queue 클래스

 Queue<T>와 달리 Queue클래스가 추가로 존재하는데, 기능이 Queue<T>보다는 많지만, 동일한 문제점이 있다.


닷넷 ConcurrentQueue 구조

 닷넷 4.0 부터 지원하는 구조이다. 기존 Queue 구조의 멀티스레드로 인한 문제가 있어서 이러한 단점을 해결하기 위한 구조이다. 기존 Queue와 큰 차이점은 인스턴스화 할때 크기를 선언하지 않는다. 이때문에 링크드 큐인것으로 생각된다.

 Enqueue는 기존 Queue와 비슷하게 사용되지만, Dequeue 대신에 TryDequeue를 사용해서 자료를 반환한다. 메서드 이름에서 알 수 있듯이 Enqueue과정이 Dequeue보다 우선 순위가 높게 구현이 되어있다. 또한 Dequeue과정이 성공/실패 여부를 반환한다. 이를 통해서 Count에 접근할 필요가 없어졌다.


유니티에서 ConcurrentQueue

 유니티에서는 닷넷을 사용할 경우 2.0에 해당되기 때문에 공식적으로 ConcurrentQueue를 사용할 수 없다. lock을 활용하여 크리티컬 섹션을 잘 설정하자.


참조 자료

스택오버 플로워

MSDN Queue

MSDN ConcurrentQueue



반응형

'C#' 카테고리의 다른 글

C# : this와 base  (0) 2018.02.20
C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : 닷넷에서 Broadcast UDP를 보내기(1)  (0) 2018.01.29
C# : const vs readonly  (0) 2017.10.25
C# 싱글톤 패턴 상속용 클래스  (0) 2017.09.29
반응형

C# : 닷넷에서 Broadcast UDP를 보내기(1)

알게된 배경

회사에서 임베이드 분야로 소켓 프로그램을 만들어야 할 일이 있었다. 물론 디바이스 단이 아니라 클라이언트 단의 프로그램이다. 임베이드 분야는 통신을 주로 실시간으로 해야 하며, 단거리 통신을 많이 하기 때문에 TCP 통신보다는 UDP 통신을 많이 사용한다. 특히 동시에 여러대의 디바이스에 신호를 주기 가장 적합한 방식은 Broadcast UDP 방식이다.


Broadcast UDP 란?

이름대로 특정망에 연결된 기기들에게 거의 동시에 동일한 UDP신호를 정해진 포트로 보내는 방식이다. 여기서 거의 동시라는 건 라즈베리 파이같은 기기로 테스트해 본 결과 0.01초 내외의 오차가 있다. 이는 디바이스의 상태와 성능에 따라 조금씩 차이가 있는 것으로 보인다.


Broadcast UDP 원리

사실 원리라고 말하기는 애매하고 규약이라 보는 것이 나을 것이다. 규약조건은 IPv4 기준으로 망을 제공하는 네트워크의 서브 마스크에서 허용되는 IPv4 주소의 비트가 1이 되게 보내면 해당신호는 Broadcast로 인식이 된다. 따라서 Broadcast UDP를 보내기 위해서는 해당 네트워크 망의 서브넷 마스크와 네트워크 제공 IP주소 체계를 알아야 한다.


[보조 설명] 서븐넷 마스크와 Broadcast UDP

서브넷 마스크 주소체계의 고정값과 비고정값을 구분하는 기준이라고 생각하면 된다. 마스크라는 단어의 의미 자체가 가면 혹은 가린다는 뜻이다. 네트워크의 신호는 주로 비트로 표현이 되는데, 마스크의 비트가 1일 경우 해당 값은 가려지는 것이고, 반대로 0 이 되는 부분은 가려지지 않은 값이다.

즉, 255.255.255.0 이라고 할경우 255는 비트상 모두 1이 되어서 255가 되는 부분은 가려져서 내부망 주소에서 구분을 하지 않는다. 반면 0인 부분은 8비트를 가리지 않아서 이론상 0~255의 주소를 구분할 수 있다.

다만, 서브마스크로 가려지지 않은 모든 비트값이 1이 될 경우에는 받는 UDP신호는 Broadcast UDP로 인식이 되어서 특정 IP가 아닌 모든 디바이스에 동일하게 전송하도록 약속이 되어 있다.



소스코드

Broadcast UDP의 규약과 구글 검색을 통한 MSDN 문서를 좀 더 찾아보면 간단히 찾아 볼 수 있다. 물론 스택오버플로어의 내용에다가 약간의 문자열을 파지 하는 방법도 있지만, 가능하면 MS에서 만들어 놓은 class를 활용을 해보도록 하자.


using System;
using System.Net.NetworkInformation;

class Program
{

// print ip address, submask
private void PrintIpAddressAndSubmask()
{
    NetworkInterface[] netInter = NetworkInterface.GetAllNetworkInterfaces();
    foreach(var itInter in netInter)
    {
        // 인터넷 혹은 망에 연결된 것만 남김
        if(itInter.OperationsalStatus != OperationalStatus.Up)
            continue;
        // 유선(Ethernet)과 무선(Wireless80211)만 남김
        if(itInter.NetworkInterfaceType != NetworkInterfaceType.Ethernet
            && itInter.NetworkInterfaceType != NetworkInterfaceType.Wireless80211)
            continue;
        var unicast = itInter.GetIpProperties().UnicastAddress;
        foreach(var itUnicast in unicast)
        {
            // Ip v6는 걸러냄
            if(itUnicast.IPv4Mask.Address == 0)
                continue;
            console.writeLine("\tIp Address : {0}", itUnicast.Address);
            console.writeLine("\tSubnet Mask : {0}", itUnicast.IPv4mask);
        }
    }
}

}





참조 자료

MSDN : UDP 서비스 사용 문서
MSDN : NetworkInterface 클래스



반응형

'C#' 카테고리의 다른 글

C# Winform : Detect Resize (크기 변화 감지)  (0) 2018.02.07
C# : Queue VS ConcurrentQueue  (0) 2018.02.02
C# : const vs readonly  (0) 2017.10.25
C# 싱글톤 패턴 상속용 클래스  (0) 2017.09.29
C# 싱글톤 패턴 : 동적 싱글톤  (0) 2017.09.04
반응형

C# : const vs readonly

정리하게 된 배경

C++를 주로 사용하던 사람에게는 const라는 키워드가 상당히 익숙하다. 나중에 만들어진 C#은 당연히 기존의 관용적으로 사용되는 것을 보완 하는 방식으로 발전을 하게 되었다. 문제는 C#의 기본서를 통해서 readonly와 const의 차이점에 대한 설명이 부족하다. 때문에 이를 보완하기 위하여 기록한다.


const

 constant(일정한)의 앞글자 머리에서 따왔듯이 변하지 않는다는 의미로 사용된다. 하지만, 초기 컴퓨터는 대부분 수치를 다루다보니 키워드에 대해서 "상수"로 번역이 되어진것 같다. 하지만, 실제 의미는 원 단어에서 온것 처럼 변하지 않는 것을 의미한다(물론 그 것도 메모리상에서는 숫자에 불과하긴하다). 이때문에 선언시 초기화 된 값을 읽을 수 밖에 없다.


readonly

 C#에서 등장한 키워드로 직역만 해도 앞의 const와 동일하게 의미를 갖고 있다. 그럼 같은걸 뭐하로 const와 readonly 둘 다 사용하게 만들었을까? 가독성을 높이기 위해서 일까?

 사실 const와 readonly는 차이가 있다. const의 경우 말그대로 선언시 반드시 초기화를 해줘야 한다. 하지만, readonly는 선언시 반드시 초기화 할 필요가 없다. 하지만, readonly이지 않는가? 그렇다. 클래스의 맴버변수(혹은 필드)로 있을때 한번만 정의가 될 수 있다. 즉, 생성자로 클래스의 인스턴스가 생성될때 결정되고 변하지 않는 값을 사용할때 적절하다.

 물론 프로퍼티를 사용해도 같은 기능을 충분히 구현할 수 있다. 다만, 이러한 기능을 사용할지 않할지는 사용하는 개발자의 몫이다.




반응형
반응형

C# 싱글톤 패턴 상속용 클래스

알게된 배경

싱글톤 패턴은 비교적 자주 사용되는 패턴이고, 멀티 스레드 프로그램을 작성할 경우 서로 상성이 안좋기 때문에 크리티컬 섹션에 대해서 뮤텍스(C#에서는 락)을 잡아줘야 한다. 문제는 이러한 패턴은 매번 반복이 되기 때문에 부모 클래스로서 작성을 해놓고, 상속받아서 기능을 구현하는 것이 여러모로 편리하다고 생각이 들기 때문에 찾아보니 해당 패턴이 있었다.

 그래서 메모겸 샘플 코드를 남긴다


부모 싱글톤

예시)

namespace Single
{
    public class Singleton<T> where T : class, new()
    {
        protected static object _instanceLock = new object();
        protected static volatile T _instance;
        public static T Instance
        {
            get
            {
                lock(_instanceLock)
                {
                    if(null == _instance)
                         _instance = new T();
                }
                return _instance;
            }
        }

    }
}



자식 싱글톤

예시)

namespace Single
{
    class MyClass : Singleton<MyClass>
    {
        // contents
        public void Print()
        {
            Console.WriteLine("Hello Singleton?");
        }
    }
}



참고자료



반응형

'C#' 카테고리의 다른 글

C# : 닷넷에서 Broadcast UDP를 보내기(1)  (0) 2018.01.29
C# : const vs readonly  (0) 2017.10.25
C# 싱글톤 패턴 : 동적 싱글톤  (0) 2017.09.04
C# Socket : 고정 구조체 만들기  (0) 2017.07.11
C# WinForm : 문자 픽셀 측정  (0) 2017.07.06
반응형

C# 싱글톤 패턴 : 동적 싱글톤

사용 목적

 하나만 있어야 하는 경우 사용되는 패턴이다. 보통 매니져 형태로 사용되는 경우에 사용된다. 간단하면서 의외로 자주 사용되는 패턴이기도 하다.

 하지만 최근에 멀티 쓰래딩을 구현할 경우 주의가 필요한 패턴이다. 보통 뮤텍스(크리티컬 섹션)와 같은 lock 기능을 통해서 동시에 접근하는 것을 막기도 하는데, 이런일이 잦을 수록 성능 향상을 저해 한다는 점도 있다.


싱글톤을 위한 기본 상식

 싱글톤(Singleton)이라는 단어에서 알 수 있듯이 하나만 존재하는 객체를 의미한다. 그래서 클래스라는 틀로 찍힌 인스턴스(실제 객체)는 하나만 존재 해야 한다.


 이 처럼 하나만 갖게 되어야 하는 조건을 충족 시키기 위해서 다음 조건들을 충족 해야 한다

 1. 생성자를 외부에서 접근되어서는 안된다(하나만 있어야 하기 때문)

 2. 인스턴스(실제 객체)는 하나만 있어야 한다.


 특히 1번의 조건을 충족하기 위해서 대부분 클래스를 지원하는 언어에서는 생성자를 private 혹은 protected 로 정의하여 외부에서 접근을 못하도록 막는 패턴을 갖게 된다.

 2번의 조건을 충족시키기 위해서는 내부에 인스턴스를 갖고 있되 접근이 가능하도록 해야 한다. 따라서 이를 위해 static으로 선언을 하게 된다. 이렇게 선언된 변수 혹은 객체는 해당 클래스를 통해서만 접근이 가능하게 된다. 그와 동시에 글로벌 영역에 객체가 존재하게 된다.

 그리고 마지막으로 싱글톤을 사용할 수 있도록 Instance 메서드를 만든다. C++의 경우 GetInstance()로 선언하는것이 관용적이지만, C#에서는 프로퍼티 기능이 있기 때문에 Get 관용구를 생략하는 경우가 있다.


구현 방법

동적 싱글톤 패턴 이기 때문에 인스턴스를 요청할때 없는 경우 생성해서 인스턴스를 반환하게 구현하면 된다.

예시)

using System;
public class Singleton
{
    private static Singleton _instance;
    private Singleton() {}
    public static Singleton Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
}




위는 정석적인 방법이고 편의상 ? 연산을 이용하여 한줄로 선언할 수 있다. 이러한 방법은 코드를 간결하게 하지만, lock을 이용한 크리티컬 섹션을 설정할 수 없는 단점이 있다.

예시)

using System;
public class Singleton
{
    private static Singleton _instance;
    private Singleton() {}
    public static Singleton Instance
    {
        get
        {
            return (null == _instance) ? _instance = new Singleton() : _instance;
        }
    }
}




참조 자료

MSDN 싱글톤 패턴 문서



반응형

+ Recent posts