RGB 영상에서의 픽셀 데이터 구성에 대해 알아봅니다.

 

 

 

1. DICOM RGB 영상.

 

DICOM Tag PhotometricInterpretation(0028,0004)이 RGB인 영상입니다.

 

RGB 영상은 각 픽셀의 색상을 빨간색, 녹색, 파란색의 세 가지 채널로 이루어져 있으며 세 채널의 조합으로 모든 색상을 표현할 수 있습니다.

 

 

 

2. Planar Configuration

 

RGB 영상의 픽셀데이터 구성에 대해 알기 위해선 먼저 PlanarConfiguration(0028,0006) 태그를 먼저 확인해야 합니다.

 

이 태그는 DICOM 이미지에서 색상 채널 데이터가 어떻게 배열되는지를 정의하는 DICOM 태그입니다. 해당 값은 0 혹인 1로 표시되며 각각 다음을 의미합니다.

 

0인 경우 RGB 채널이 인터리브(Interleaved)하게 이루어져 있습니다. Color-by-pixel 방식이라고도 하며 모든 채널의 데이터를 교대로 저장하여 RGB 데이터가 연속된 형식으로 존재합니다. 이는 각 픽셀에 해당하는 RGB값이 연속적으로 저장됨을 뜻합니다. 예: [R0, G0, B0, R1, G1, B1, ...]

 

1인경우 RGB 채널이 플래너(Planar)하게 이루어져 있습니다. Color-by-plane 방식이라고도 합니다. 각 색상 채널이 별도의 2D 이미지로 저장되며, 각 채널이 독립적으로 배열됩니다. 이는 각 색상 채널이 개별적으로 저장되어 있음을 뜻합니다. 예: 예: [R0, R1, R2, ..., Gn, Gm, Gn+1, ..., Bn, Bm, Bn+1, ...]

 

 

 

3. BitAllocated와 BitStored

 

DICOM에서 픽셀 데이터를 다루기 위해선 또 다른 태그를 더 살펴봐야 합니다.

 

Bit Allocated(0028,0100)는 각 픽셀에 할당된 총 비트 수를 의미하며 일반적으로 8, 12, 16 비트가 사용됩니다.  Bits Stored(0028,0101)는 각 픽셀에 저장된 실제 유효 비트 수를 의미합니다.

 

예를 들어, Bits Allocated가 16이고, Bits Stored가 12이면, 각 픽셀 데이터는 16비트로 저장되지만, 그중 12비트만 유효 데이터로 사용됩니다. 나머지 4비트는 일반적으로 0으로 채워짐을 의미합니다.

 

 

 

4. 픽셀 데이터 계산

 

이제 기본적인 태그(rows 및 colums)를 사용해 RGB 영상의 픽셀 데이터 위치를 알아낼 수 있습니다. 

 

PlanarConfiguration이 1일 때 rows(H)와 columns(W)가 512인 경우 x, y좌표 300, 250의 RGB값은 다음과 같이 구할 수 있습니다.

    ⇒ 한 프레임의 픽셀 수: W x H
    ⇒ 한 프레임의 채널 데이터 크기: W x H
    ⇒ 한 프레임의 전체 데이터 크기: 3 x W x H

여기서 각 프레임의 데이터는 연속적으로 저장되므로, N번째 프레임의 시작 위치는 다음과 같이 계산할 수 있습니다

    ⇒ N번째 프레임의 시작 위치: (N-1) * 3 * W * H

PlanarConfiguration이 1이므로 각채널의 시작위치는 다음과 같이 유추할 수 있습니다.

    ⇒  Red 채널의 시작 위치: (N-1) * 3 * W * H
    ⇒  Green 채널의 시작 위치: (N-1) * 3 * W * H + W * H
    ⇒  Blue 채널의 시작 위치: (N-1) * 3 * W * H + 2 * W * H

마지막으로 실제 우리가 원하는 픽셀의 인덱스 위치는 다음과 같이 계산할 수 있습니다.

    ⇒ 픽셀 인덱스: y * W + x

따라서 위의 모든 식을 종합하면 PlanarConfiguration이 1일 때 rows(H)와 columns(W)가 512인 경우 x, y좌표 300, 250의 RGB의 위치는 다음과 같이 산출됩니다.

    ⇒ Red 값의 위치: (N-1) * ( 3 x W x H)+ (y * W + x)
    ⇒ Green 값의 위치: (N-1) * ( 3 x W x H) + (W * H)+ (y * W + x)
    ⇒ Blue 값의 위치: (N-1) * ( 3 x W x H) + (2 * W * H) + (y * W + x)

 

다음으로 PlanarConfiguration이 0일 때 rows(H)와 columns(W)가 512인 경우 x, y좌표 300, 250의 RGB값은 다음과 같이 구할 수 있습니다.

    ⇒ 한 프레임의 픽셀 수: W x H
    ⇒ 한 프레임의 전체 데이터 크기: 3 x W x H

여기서 각 프레임의 데이터는 연속적으로 저장되므로, N번째 프레임의 시작 위치는 다음과 같이 계산할 수 있습니다

    ⇒ N번째 프레임의 시작 위치: (N-1) * 3 * W * H

다음으로 우리가 원하는 픽셀의 인덱스 위치는 다음과 같이 계산할 수 있습니다.

    ⇒ 픽셀 인덱스: y * W + x

PlanarConfiguration이 0이므로, 각 픽셀의 R, G, B 값이 연속적으로 저장됩니다. 따라서, N번째 프레임의 시작 위치에서 해당 픽셀 인덱스를 3배 한 값이 각 채널의 시작 위치가 됩니다.

    ⇒ Red   값의 위치: (N-1) * (3 * W * H) + 3 * (y * W + x)
    ⇒ Green   값의 위치: (N-1) * (3 * W * H) + 3 *  (y * W + x) + 1
    ⇒ Blue   값의 위치: (N-1) * (3 * W * H) + 3 *  (y * W + x) + 2

 

이제 해당 값을 이용해 픽셀 데이터를 원하는 값으로 수정할 수 있습니다.

 

 

 

 

 

 

반응형

 

 

 

Keyclock 컨테이너를 postgresql db와 함께 사용하는 방법에 대하 알아봅니다.

 

 

 

0. 참고

 

jbos/keycloak는 더 이상 관리되지 않습니다. 현재 글 작성 시점에 dockerhub에는 공식 keycloak 이미지가 배포되고 있지 않습니다. 

 

 

 

1. docker-compose.yml

 

다음과 같이 docker-compose.yml을 작성합니다.

 

version: '3.8'

services:
  keycloak:
    image: quay.io/keycloak/keycloak:24.0.2
    ports:
      - "8080:8080"
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://your.dbhost.com:5432/yourdbname
      KC_DB_USERNAME: yourdbuser
      KC_DB_PASSWORD: yourdbpassword
      KC_HTTP_ENABLED: true
      KC_HEALTH_ENABLED: true
      KEYCLOAK_ADMIN: yourkeycloakuser
      KEYCLOAK_ADMIN_PASSWORD: yourkeycloakpassword
    command: 
      - start-dev 
      - --import-realm
    volumes:
      - /home/keycloak/realm.json:/opt/keycloak/data/import/realm.json

 

환경 변수에대해 간단하게 설명하자면 다음과 같습니다.

  • KC_DB: 사용할 데이터베이스의 종류입니다. postgres로 두면 됩니다.
  • KC_DB_URL: postgres 접속 정보입니다. host, port, db이름을 변경해 사용하시면 됩니다.
  • KC_DB_USERNAME: DB 접속 계정 정보입니다. 변경해 사용하시면 됩니다.
  • KC_DB_PASSWORD: DB 접속 계정의 암호입니다. 변경해 사용하시면 됩니다.
  • KC_HTTP_ENABLE: HTTP를 통해 접근 가능한지 여부를 결정합니다. 
  • KC_HEALTH_ENABLED: 상태 확인 엔드포인트를 활성화할지 여부를 결정합니다. true로 설정한 경우 다음과 같은 엔드포인트가 활성화됩니다.
    • /health/live
    • /health/ready
    • /health/started
    • /health
  • KEYCLOAK_ADMIN: 관리용 페이지에 로그인할 수 있는 계정을 설정합니다.
  • KEYCLOAK_ADMIN_PASSWORD: 관리용 페이지에 로그인 할 수 있는 계정의 암호를 설정합니다.

 

 

 

 

 

반응형

 

 

 

일반적으로 lib는 C++에서, dll은 양쪽 모두에서 사용할 수 있는 라이브러리 산출물로 알려져 있습니다.

그동안 이를 당연하게 여기고 별 의문 없이 관습적으로, 사용하던 대로 사용하곤 했습니다.

이 글에선 lib와 dll이 무엇이고 어떤점이 다르길래 왜 C#에선 lib를 사용할 수 없는지 알아보고자 합니다.

 

 

 

.lib와 .dll 파일

 

.dll 파일과 .lib 파일은 모두 C++ 프로그래밍에서 사용되는 파일 형식입니다. 하지만 그들의 역할과 구성은 다릅니다.

 

.dll 파일은 실행 중에 다른 프로그램에 의해 호출되는 코드와 데이터의 모음입니다. 이는 동적 라이브러리라고 부르며 프로그램이 실행될 때에만 필요한 함수 및 데이터를 메모리에 로드합니다.
여러 프로그램에서 공유하여 사용할 수 있으며, 코드 및 데이터의 재사용을 용이하게 합니다. dll은 주로 라이브러리나 플러그인 형태로 사용되며, 함수와 데이터를 외부에 공개하기 위한 인터페이스 역할을 합니다.

 

.lib 파일은 프로그램이 컴파일될 때 링커(Linker)에 의해 사용되는 라이브러리 파일입니다. 정적 라이브러리라고 부르며 해당 파일에 포함된 코드와 데이터가 컴파일 시에 프로그램에 직접 포함됩니다.
프로그램을 실행할 때 .lib 파일이 필요하지 않으며, 해당 파일에 포함된 코드 및 데이터가 이미 실행 파일에 포함되어 있습니다. 주로 컴파일러에 의해 생성된 객체 파일(Object File)을 묶어 놓은 형태로 사용되며, 함수 및 데이터의 정의를 포함합니다.

 

주요한 차이점은 .dll 파일이 실행 중에 필요한 코드와 데이터를 제공하는 동적 라이브러리인 반면, .lib 파일은 컴파일 시에 링크되는 정적 라이브러리입니다. 또한 .dll 파일은 외부 프로그램에서 호출되고 공유될 수 있지만, .lib 파일은 컴파일 시에 해당 프로그램에 포함되어 실행된다는 점 입니다.

 

 

 

그래서 왜 C#에서는 lib 파일을 사용할 수 없을까?

 

.lib 파일은 C++에서 사용되는 라이브러리 파일로, 컴파일러에 의해 링크되어 프로그램에 포함됩니다. 이 파일은 주로 함수와 기호의 정의를 포함하고 있을 뿐 .lib 파일 자체는 실행 코드를 포함하고 있지 않습니다.

C++에서는 컴파일 시에 .lib 파일이 필요하며, 링크 과정에서 이 파일이 사용됩니다. 그러나 C#은 .NET Framework 또는 .NET Core와 같은 가상 머신 위에서 실행되는 고수준 언어로, 직접적으로 .lib 파일을 사용하는 것은 불가능합니다.

대신에, C#에서는 Platform Invocation Services(P/Invoke)를 통해 외부 DLL에 있는 함수들을 호출할 수 있습니다. 따라서 .lib 파일을 사용하는 대신 해당 .lib 파일로부터 생성된 DLL 파일을 사용하여 P/Invoke를 통해 함수를 호출해야 합니다.

길지만 결국 근본적으로는 언어 및 런타임 환경이 서로 다르기 때문입니다.

 

C# 코드는 CLR(Common Language Runtime)이라고 불리는 가상 머신에서 실행됩니다. 이는 메모리 관리, 예외 처리 및 스레드 관리와 같은 기능을 제공합니다. 반면에 C++ 코드는 운영체제의 네이티브 코드로 컴파일되어 실행됩니다.

 

따라서 C#에서는 .lib 파일에 포함된 네이티브 코드를 직접적으로 이해하고 호출할 수 없습니다. 대신에, C#에서는 P/Invoke를 사용하여 외부 DLL 파일에 포함된 함수들을 호출할 수 있습니다. 이렇게 함으로써 C#은 외부 C++ 코드와 상호작용할 수 있습니다.

 

 

 

 

반응형

 

C#에서 LINQ와 람다(Lambda)식에 대해 알아봅니다.

 

 

 

1. LINQ란?

 

LINQ (Language-Integrated Query)는 C# 언어에 통합된 쿼리 언어입니다. 이는 데이터 소스에서 데이터를 쿼리하고 조작하는 데 사용됩니다.

 

LINQ를 사용하면 배열, 컬렉션, 데이터베이스, XML 등과 같은 다양한 데이터 소스에서 데이터를 추출하고 변환할 수 있습니다.


일반적인 LINQ 쿼리는 from, where, select와 같은 키워드를 사용하여 데이터를 선택하고 필터링하는 데에 사용됩니다.

 

int[] numbers = [ 0, 1, 2, 3, 4, 5, 6 ];

// LINQ를 이용해 짝수를 쿼리.
var evenNumbers = from num in numbers
                  where num % 2 == 0
                  select num;

 

 

 

2. 람다식(Lambda Expressions)이란?

 

람다식은 익명 함수를 간결하게 표현하는 방법입니다. 주로 LINQ와 함께 사용되며, 간단한 인라인 함수를 정의할 때 효과적입니다.


람다식의 일반적인 구문은 input => expression 형태로 표현됩니다. 여기서 input은 매개변수를 나타내고, expression은 함수의 몸체를 나타냅니다.


람다식은 더 간결하게 코드를 작성할 수 있게 해 주며, LINQ에서는 특히 읽기 쉽고 간편한 필터 및 프로젝션 작업에 자주 사용됩니다.

 

// LINQ에 람다식을 함께 사용.
var evenNumbers = numbers.Where(num => num % 2 == 0);

 

 

 

3. LINQ와 람다식

 

LINQ와 람다식을 조합하여 사용하면 코드를 간결하게 유지하면서도 더 복잡한 조건이나 작업을 처리할 수 있습니다.

 

두 가지를 조합하면 다음과 같은 이점을 얻을 수 있습니다.

1. 람다식은 코드를 더 간결하게 만들어주기 때문에 LINQ와 함께 사용하면 코드가 간편하고 가독성이 높아집니다.

2. 람다식을 사용하면 더 복잡한 조건을 지정할 수 있고, 필요에 따라 쉽게 추가 또는 수정할 수 있습니다.

3. LINQ 메서드와 람다식을 함께 사용하면 메서드 체이닝을 통해 여러 작업을 한 줄로 연결할 수 있습니다.

4. 간단한 연산이나 프로젝션을 람다식 내에서 인라인으로 정의할 수 있어 코드를 더 직관적으로 만들 수 있습니다.

 

 

 

 

 

 

반응형

 

클래스를 어떻게 분리할 것인가?

 

일반적으로 객체 지향 프로그래밍 중 클래스에 코드를 구현하다 보면 어? 코드가 너무 많은데? 하는 순간이 찾아옵니다.
보통은 별개의 클래스로 나누어 작업을 진행합니다. 하지만 partial class를 사용하면 하나의 클래스를 여러 파일로 나누어 작업을 진행할 수 있습니다.

 

 

작업을 별도의 클래스로 분리하는 경우:

 

별도의 클래스로 분리하는 경우 단일 책임 원칙 (Single Responsibility Principle)을 지킬 수 있다는 장점이 있습니다.

클래스는 하나의 책임만 가져야 한다는 원칙에 따라, 작업을 별도의 클래스로 분리하면 각 클래스는 더 작은 하나의 책임만 지도록 할 수 있습니다..

 

또한 모듈화를 통한 재사용성 향상을 기대할 수 있습니다.

작업을 별도의 클래스로 분리하면 해당 작업을 다른 부분에서 재사용하기 용이합니다.

 

이로 인해 테스트 용이성이 향상됩니다.

분리된 클래스는 독립적으로 테스트하기 쉽기 때문에 단위 테스트가 용이합니다.

 

하지만 클래스 수 증가로 인한 복잡도 증가가 발생할 수 있습니다.

여러 작업을 별도의 클래스로 나누면 클래스 수가 증가하게 됩니다. 클래스가 많아지면 전체적인 코드의 이해와 유지보수가 어려워질 수 있습니다.

 

 

 

partial 클래스로 나누어 구현하는 경우:

 

partial 클래스를 사용하면 단일 클래스 내에서 논리적 구분이 가능해집니다.

partial 클래스를 사용하면 논리적으로 관련된 코드를 동일한 클래스 내에서 나누어 구현할 수 있습니다. 이로써 클래스의 응집성(cohesion)을 높일 수 있다는 장점을 갖게 됩니다.

 

또한 모듈화 시켜 코드를 작성함과 동시에 컴파일 시 통합되기 때문에 코드의 가독성을 높일 수 있습니다.

partial 클래스를 컴파일 시에 하나의 클래스로 통합되기 때문에 코드를 나누어 작성하더라도 최종적으로는 하나의 클래스로 구현됩니다. 따라서 코드의 가독성을 높일 수 있습니다.

 

 

결론

 

만약 프로젝트에 대한 미리 정의된 코딩 가이드가 있다면 그것을 따르는 것이 좋습니다.

일반적으로는 단일 책임 원칙을 준수하고 모듈화와 재사용성을 높일 수 있는 방향으로 작업을 분리하는 것이 좋습니다. 

하지만 프로젝트의 구조나 특정한 상황에 따라서는 partial 클래스를 사용하여 클래스의 일부를 나누는 것이 효과적일 수 있습니다. 

가장 좋은 방법은 둘 다 사용해 본 뒤 자신의 상황에 적절한 방식을 선택하는 것입니다.

 

반응형

 

 

팔월드 멀티 비밀번호방 접속 방법에 대해 알아봅니다. 해당 글은 현재 얼리액세스 버전인 v.0.1.2 버전에 맞춰서 작성하였습니다.

 

게임이 아직 얼리액세스이다 보니 전용서버에 암호와 함께 직접 접속하는 방법이 없습니다. 따라서 커뮤니티 서버에서 검색해서 게임에 접속하시거나 다음 방법을 사용하시면 됩니다.

 

 

먼저 "멀티 플레이 참가하기(전용서버)"를 클릭 한 뒤 "커뮤니티 서버"에서 IP 및 포트를 직접 입력해 접속을 시도합니다.

 

 

그럼 위와 같이 암호를 입력해야 한다는 오류와 함께 방 입장에 실패합니다. 만약 타임아웃 메시지가 나왔다면 서버에 문제가 있는것으로 서버 호스트에 문의해야 합니다.

 

 

저 에러 메시지를 본 뒤 다시 "멀티 플레이 참가하기(전용서버)"를 클릭 한 뒤 "최근 접속한 서버"로 이동하면 아까 입장에 실패했던 방이 있습니다.

 

 

이제 저 방을 클릭하고 암호를 입력 한 뒤 게임을 즐기시면 됩니다.

 

 

 

 

 

반응형

 

요즘 핫한 게임 팔월드. 친구들과 함께 즐기기 위해 전용 서버를 구축하며 발생한 시행착오와 구축 방법에 대해 정리합니다.

 

 

 

0. 준비

 

전용 서버를 구동할 PC 혹은 서버

** 전 Ubuntu 서버에 구축하였습니다. SteamCmd를 설치하는 방법부터 설명하오니 Windows를 사용하는 분은 "2. PalWorld Dedicated Server 설치"부터 읽어주시면 됩니다.

 

 

 

1. SteamCmd 설치

 

당연하지만 가장 먼저 스팀을 설치해야 합니다. 만약 GUI가 지원되는 PC라면 웹 브라우저를 열고 Steam 페이지로 들어가 Steam을 설치합니다.

 

만약 GUI를 지원하지 않으면 CMD를 설치해야 합니다.  다음 명령어로 steam이라는 유저를 생성(Steam 로그인 계정이 아닙니다.)합니다.

 

> sudo useradd -m steam
> sudo passwd steam

 

유저를 생성한 뒤 권한을 부여해야 합니다. 다음 명령어를 수행해 sudoers를 열어줍니다.

 

> sudo vi /etc/sudoers

 

이제 생성한 steam 유저에 권한을 부여합니다. " root ALL=(ALL:ALL:) ALL"를 찾아 그 아래애 다음과 같이 추가합니다.

...
root ALL=(ALL:ALL:) ALL
steam ALL=(ALL:ALL) ALL
...

 

다음엔 생성한 steam 유저로 로그인해 SteamCmd를 설치합니다.

 

> sudo useradd -m steam
> sudo passwd steam
> sudo add-apt-repository multiverse; sudo dpkg --add-architecture i386; sudo apt update
> sudo apt install steamcmd

 

 

 

 

2. PalWorld Dedicated Server 설치

 

먼저 Windows나 Ubuntu Desktop(GUI)를 사용한다면 Steam을 열고 라이브러리로 이동한 다음 " PalWorld Dedicated Server"를 설치하면 됩니다.

 

 

간단하게 PalWorld Dedicated Server 설치가 끝났습니다. "3. 서버 설정"으로 가서 나머지 글을 읽어주세요.

 

만약 Ubuntu Server(CLI)를 사용한다면 다음 명령어를 통해 PalWorld Dedicated Server를 설치해야 합니다.

 

> steamcmd +login anonymous +app_update 2394010 validate +quit
> cd ~/Steam/steamapps/common/PalServer
> ./PalServer.sh

 

./PalServer.sh 명령어를 수행하면 자동으로 전용 서버가 시작됩니다. 만약 다음과 같은 오류가 발생한다면 추가 명령어 수행이 필요합니다.

 

.steam/sdk64/steamclient.so: cannot open shared object file: No such file or directory

 

터미널에 위와 같은 오류가 있다면 다음 명령어를 수행해 줍시다.

 

> mkdir -p ~/.steam/sdk64/
> steamcmd +login anonymous +app_update 1007 +quit
> cp ~/Steam/steamapps/common/Steamworks\ SDK\ Redist/linux64/steamclient.so ~/.steam/sdk64/

 

이제 다시 ./PalServer.sh를 수행하면 정상적으로 서버가 구동됩니다.

 

** 참고: 다음과 같은 오류가 발생하는 것은 정상으로 서버 구동에 문제가 없습니다.

$ ./PalServer.sh
Shutdown handler: initalize.
Increasing per-process limit of core file size to infinity.
dlopen failed trying to load: steamclient.so with error: steamclient.so: cannot open shared object file: No such file or directory
[S_API] SteamAPI_Init(): Loaded '/home/ubuntu/.steam/sdk64/steamclient.so' OK. (First tried local 'steamclient.so')

 

 

 

 

3. 서버 설정

 

이제 다른 친구들이 내 서버에 접속할 수 있게 만들어야 합니다. 만약 자신이 퍼블릭 IP를 직접 사용하고 있다면 이 설명은 스킵하셔도 됩니다.

 

하지만 내 전용 서버가 공유기에 연결되어 있는 경우에는 포트포워딩이 필요합니다. 포트포워딩의 개념이나 원리에 대해서는 스킵하고 설정하는 방법에 대해서만 설명합니다.

 

먼저 크롬과 같은 웹 브라우저를 열고 http://192.168.0.1/의 주소(IPTime 공유기 기준)로 이동합니다.

 

 

보안 인증을 하고 로그인 한 뒤 관리도구 > 고급설정 > NAT/라우터 구성 > 포트포워드 설정으로 이동합니다.

 

 

이제 위와 같이 PalServer에 대한 포트포워드 구성을 진행합니다. 최소 하나의 항목을 추가해야 합니다.

 

 

1. 규칙이름: 포트포워드 설정을 구성하는 이름입니다. 

2. 내부 IP 추소: 전용 서버가 설치된 PC의 IP 주소입니다. 만약 관리페이지를 전용 서버가 설치된 PC에서 들어갔다면 체크박스를 클릭해 간단하게 설정합니다.

3. 프로토콜: 해당 포트를 사용하는 프로토콜입니다. PalWorld는 기본적으로 UDP를 사용하는 것으로 알려져 있습니다  전 그냥 둘 다 활성화시켜놨습니다.

4. 외부 포트: 외부망에서 공유기로 접속할 때 사용하는 포트입니다. 포트포워드 설정에 겹치지 않게 적절하게 수정하셔도 됩니다.

5. 내부포트: 전용서버가 사용하는 포트입니다. PalWorld는 기본적으로 8211 포트를 사용합니다

 

** 참고: 내부포트 8211은 서버에서 사용하고 27015는 Query에, 25575는 RCON에 사용된다고 알려져 있습니다. 서버만 구동하는 데에는 8211 포트만 설정해도 서버는 구동됩니다. 

 

 

 

4. 게임 설정

 

이제 서버 설정이 끝났습니다. 이제 인게임 설정을 진행합시다. 내가 만든 서버가 공개되어 아무나 들어오게 하고 싶진 않습니다. 방정보와 비밀번호를 설정해 봅시다.

 

서버 설정파일은 다음에 위치하고 있습니다.

Windows: \Steam\steamapps\common\PalServer\Pal\Saved\Config\WindowsServer\PalWorldSettings.ini

Linux: ~/Steam/steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini

 

서버 설정의 기본값은 다음에 위치하고 있습니다.

Windows: \Steam\steamapps\common\PalServer\DefaultPalWorldSettings.ini

Linux:  ~/Steam/steamapps/common/PalServer/DefaultPalWorldSettings.ini

 

DefaultPalWorldSettings.ini에 있는 내용을 복사해 PalWorldSettings.ini에 적용시키면 됩니다.

[/Script/Pal.PalGameWorldSettings]
OptionSettings=(Difficulty=None,DayTimeSpeedRate=1.000000,NightTimeSpeedRate=1.000000,ExpRate=1.000000,PalCaptureRate=1.000000,PalSpawnNumRate=1.000000,PalDamageRateAttack=1.000000,PalDamageRateDefense=1.000000,PlayerDamageRateAttack=1.000000,PlayerDamageRateDefense=1.000000,PlayerStomachDecreaceRate=1.000000,PlayerStaminaDecreaceRate=1.000000,PlayerAutoHPRegeneRate=1.000000,PlayerAutoHpRegeneRateInSleep=1.000000,PalStomachDecreaceRate=1.000000,PalStaminaDecreaceRate=1.000000,PalAutoHPRegeneRate=1.000000,PalAutoHpRegeneRateInSleep=1.000000,BuildObjectDamageRate=1.000000,BuildObjectDeteriorationDamageRate=1.000000,CollectionDropRate=1.000000,CollectionObjectHpRate=1.000000,CollectionObjectRespawnSpeedRate=1.000000,EnemyDropItemRate=1.000000,DeathPenalty=All,bEnablePlayerToPlayerDamage=False,bEnableFriendlyFire=False,bEnableInvaderEnemy=True,bActiveUNKO=False,bEnableAimAssistPad=True,bEnableAimAssistKeyboard=False,DropItemMaxNum=3000,DropItemMaxNum_UNKO=100,BaseCampMaxNum=128,BaseCampWorkerMaxNum=15,DropItemAliveMaxHours=1.000000,bAutoResetGuildNoOnlinePlayers=False,AutoResetGuildTimeNoOnlinePlayers=72.000000,GuildPlayerMaxNum=20,PalEggDefaultHatchingTime=72.000000,WorkSpeedRate=1.000000,bIsMultiplay=False,bIsPvP=False,bCanPickupOtherGuildDeathPenaltyDrop=False,bEnableNonLoginPenalty=True,bEnableFastTravel=True,bIsStartLocationSelectByMap=True,bExistPlayerAfterLogout=False,bEnableDefenseOtherGuildPlayer=False,CoopPlayerMaxNum=4,ServerPlayerMaxNum=32,ServerName="Default Palworld Server",ServerDescription="",AdminPassword="",ServerPassword="",PublicPort=8211,PublicIP="",RCONEnabled=False,RCONPort=25575,Region="",bUseAuth=True,BanListURL="https://api.palworldgame.com/api/banlist.txt")

 

딱 두줄만 복사하면 됩니다. 줄 바꿈을 하시면 안됩니다. 줄바꿈을 하는 경우 설정이 무효화되어 이전 설정값으로 바뀌거나 기본 설정값이 사용됩니다.

(수정) 줄바꿈해도 적용 됩니다. 다만, 게임이 실행중일떄 설정을 바꾼 후 게임을 종료하게되면 기존 게임 설정으로 롤백됩니다. 미리 설정을 바꾸고 서버를 빠르게 재시작하려고 했는데 설정이 롤백되는것을 확인했습니다.

 

자세한 설정값은 공식 홈페이지(Optimize game balance, Settings)에서 확인 후 변경하시면 됩니다.

 

간단하게 방 이름과 암호만 바꾸려면 다음 값을 수정해 주시면 됩니다.

 

1. ServerName="Default Palworld Server" => 방 이름을 변경합니다.

2. ServerPassword="" => 방에 접속할 때 비밀번호를 설정합니다.

3. AdminPassword="" => 방에 접속 후 관리자 명령어를 사용할 떄 필요합니다.

 

관리자 명령어는 마인크래프트에서 tp 같은 명령어를 사용할 때 쓰는 것과 동일하다고 생각하시면 됩니다. 관리자 명령어는 공식 홈페이지(Commands)에서 확인하실 수 있습니다.

 

이제 서버를 구동합시다.

Windows: \Steam\steamapps\common\PalServer\PalServer.exe

Linux: ~/Steam/steamapps/common/PalServer/PalServer.sh

 

 

 

5. 접속: 암호가 있는 방에 IP로 접속하기

 

게임이 아직 얼리액세스이다 보니 전용서버에 암호와 함께 직접 접속하는 방법이 없습니다. 따라서 커뮤니티 서버에서 검색해서 게임에 접속하시거나 다음 방법을 사용하시면 됩니다.

 

* 커뮤니티 서버 검색 후 접속

 

 

가장 기본적인 접속 방법입니다. 방 이름을 검색해 접속하면 됩니다. 방을 선택하면 비밀번호를 입력하는 화면이 나와 비밀번호를 입력하고 접속하면 됩니다.

 

하지만 이 방법의 경우 전용 서버가 제대로 검색되지 않는 경우가 많이 발생합니다. 따라서 다음과 같이 접속하는 방법을 사용해서 비밀 방에 접속할 수도 있습니다.

 

* 직접 접속하기.

 

 

일단 그림과 같이 IP와 포트를 입력해 직접 접속합니다.

 

 

우린 암호를 입력하지 않았으므로 접속에 실패합니다. 다시 전용서버 화면으로 이동합니다. 이번에는 직접 IP를 입력하는 게 아니라 "최근 접속한 서버"를 클릭합니다.

 

 

그럼 방금 전에 접속시도한 서버가 보입니다. 이제 암호를 입력하고 접속해 게임을 즐기시면 됩니다.

 

 

 

 

 

 

반응형

 

DICOM 통신에 기본이 되는 PDU와 PDV에 대해 알아봅니다.

 

1. PDU - Protocol Data Unit

 

https://www.dicomstandard.org/current

 

위의 그림은 DICOM UL 중 A-ASSOCIATE-RQ PDU와 A-ASSOCIATE-AC PDU의 PDU 인코딩의 예시입니다.

 

PDU(Protocol Data Unit)는 계층 내의 피어 엔터티 간에 교환되는 메시지 형식입니다. PDU는 프로토콜 제어 정보와 사용자 데이터로 구성됩니다. PDU는 필수 고정 필드와 하나 이상의 항목 및/또는 하위 항목을 포함하는 선택적 가변 필드로 구성됩니다. 

 

정리하자면

* PDU는 네트워크 통신에서 데이터를 전송하는 데 사용되는 단위입니다.
* DICOM에서 PDU는 네트워크 상에서 DICOM 메시지를 나타내는 단위를 말합니다.
* PDU는 DICOM 메시지의 헤더 정보와 함께 전송되어야 합니다.
* DICOM 네트워크 프로토콜에서는 PDU가 통신의 기본적인 단위로 사용되며, 여러 종류의 PDU가 정의되어 있습니다.

 

 

 

2. PDV - Presentation-data-value

 

PDV는 DICOM 메시지의 일부로, 특히 DICOM 데이터를 전송하는 데 사용됩니다. DICOM 메시지는 PDU (Protocol Data Unit)의 일부로 전송되며, PDU에는 여러 PDV가 포함될 수 있습니다. 

 

PDV는 실제 DICOM 데이터를 담고 있는 부분으로 다양한 종류의 PDV가 존재하고, 각 PDV 유형은 특정한 역할을 수행합니다.

 

정리하자면

* PDV는 PDU 내에서 실제 데이터를 포함하는 부분을 나타냅니다.
* PDU는 여러 PDV를 포함할 수 있습니다.
* PDV는 DICOM 메시지의 일부로, 실제 DICOM 데이터를 포함하고 있습니다.
* PDV는 PDU의 일부로 전송되어, 네트워크 상에서 DICOM 데이터의 전송을 담당합니다.

 

 

 

 

 

 

 

 

반응형

 

 

 

0. 앞선 글

 

Docker 이미지의 태그들 중에서 -alpine이라는 태그가 달려있는 이미지들을 자주 볼 수 있습니다. 이 글에선 alpine이 무엇인지, 왜 사용하는지에 대해서 알아봅니다.

 

이 글은 The 3 Biggest Wins When Using Alpine as a Base Docker Image을 번역 한 글입니다.

 

 

 

1. Alpine?

 

Alpine은 다음과 같이 설명됩니다.

 

Small. Simple. Secure. Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.
- 가볍고 단순하며 안전합니다. 알파인 리눅스는 musl libc와 busybox를 기반으로 한 보안지향의 경량 리눅스 배포판입니다.

 

 

 

2. 가장 큰 이점은 컨테이너의 용량이 작아진다는 것입니다.

 

세탁과 같은 상황에서 줄어든다는 것은 나쁜 상황이겠지만 Docker의 세계에서는 Docker 이미지가 더 작아진다는 의미이므로 기대할만한 상황이 됩니다.

Alpine 3.6의 Dockerized 버전의 무게는 3.98MB입니다.

비교를 위해 Alpine을 다른 인기 Linux 배포판과 비교해 보자면 그 크기는 다음 표와 같습니다: 

DISTRIBUTION VERSION SIZE
Debian Jessie 123MB
CentOS 7 193MB
Fedora 25 231MB
Ubuntu 16.04 118MB
Alpine 3.6 3.98MB

 

크기 차이 좀 보세요. 알파인은 데비안보다 약 30배 작습니다.

Docker Hub는 수많은 풀을 처리합니다. API를 조사해 보면 이 글이 작성되는 시점(2017년도 기준)에 Debian에 35,555,107개의 pull이, Alpine은 135,136,475개의 pull이 있었음을 알 수 있습니다.

이러한 pull로 인해 모든 바이트가 전송될까요? 아마도 그렇지 않을 것입니다. 그러나 당신이 한 예상은 제가 한 것처럼 좋을 것입니다. 최소한 상황을 보는 관점은 되어줍니다.

 

S3를 통해 Debian과 Alpine을 최대 3,500만 번 전송하는 데 드는 예상 비용:

DISTRIBUTION GIGS TRANSFERRED S3 TRANSFER COST
Debian 4,373,278 $416,310.72
Alpine 141,509 $17,832.06

 

S3의 가격 계산기 비용으로 Debian과 Alpine을 최대 3,500만 번 전송하는 데 거의 $400,000 USD의 차이가 발생하게 됩니다..

아마도 여러분이 그 정도의 규모로 운영하고 있지 않을 것이라는 건 압니다. 그러나 모든 규모 수준에서 클라우드의 전송 비용에 있어서는 실질적인 절감 효과가 있습니다.

이미지 크기를 100MB 이상 줄일 수 있다는 것은 큰 일입니다.

많은 패키지가 설치된 실제 웹 애플리케이션에서 Alpine을 사용하면 최종 이미지 크기가 2배 또는 3배 정도 절약되므로 마이크로 벤치마크에만 유용한 것은 아닙니다. 최대 100MB 절약은 이미지에 무엇이 내장되어 있는지에 관계없이 고정되어 있는 이점입니다.

 

 

3. 알파인은 빠릅니다.

 

더 작은 Docker 이미지를 처리할 때 비용만이 유일한 장점은 아닙니다.

Docker 이미지를 다운로드하고  CURL을 설치하고 싶다고 가정해 보겠습니다. Debian과 Alpine의 경우 시간이 얼마나 걸릴까요?

 

여기서는 2가지 테스트를 수행하겠습니다.

첫 번째 테스트는 30MB 가정용 케이블 연결을 사용하여 기본 Docker 이미지를 시스템에 다운로드하고 CURL을 설치할 것이며 시스템에 이미지가 다운로드되어있지 않은 환경입니다.

두 번째 테스트는 CURL을 설치하기 전에 시스템에 이미 기본 Docker 이미지가 있다는 점을 제외하면 위와 동일합니다.

 

테스트 1의 결과:

## Debian
time docker run --rm debian sh -c "apt-get update && apt-get install curl"
real 0m 27.928s
user 0m 0.019s
sys 0m 0.077s

 

Debian을 모두 다운로드하고 apt-get 업데이트를 실행한 다음 CURL을 설치하는 데 실제 시간은 약 28초입니다.

 

## Alpine
time docker run --rm alpine sh -c "apk update && apk add curl"
real 0m 5.698s
user 0m 0.008s
sys 0m 0.037s

 

반면에 Alpine을 사용하면 약 5배 더 빠르게 완료되었습니다. 28초와 5초를 기다리는 것을 비교하는 건 가벼운 게 아닙니다. 상당한 시간입니다.

프로그래밍 테스트가 30초 또는 5초 안에 완료될 때까지 기다리는 것이 얼마나 짜증 나는 일인지 생각해 보십시오.

 

테스트 2의 결과:

## Debian
time docker run --rm debian sh -c "apt-get update && apt-get install curl"
real 0m 9.170s
user 0m 0.000s
sys 0m 0.031s

 

분명히 30MB 케이블이 병목 현상을 일으키고 있어 apt-get update를 실행하고 컬을 설치하는 데에는 9초 이상이 걸렸습니다.

 

##Alpine

time docker run --rm alpine sh -c "apk update && apk add curl"
real 0m 3.040s
user 0m 0.017s
sys 0m 0.008s

 

반면 알파인은 단 3초 만에 완료했습니다. 약 3배 정도 개선된 셈입니다.

 

새 Docker 이미지를 새로운 서버로 다운로드할 때 Alpine에서 초기 풀링 속도가 상당히 빨라질 것으로 예상할 수 있습니다. 네트워크 속도가 느릴수록 그 차이는 더 커집니다.

자동 확장 기능이 있고 많은 서버를 가동하는 경우라면 이는 매우 큰 문제입니다. 이는 서버가 더 빠른 속도로 트래픽을 수용할 준비가 되었음을 의미합니다.

서버를 많이 가동하지 않으면 속도 이점이 크게 떨어지지만 데이터 전송 및 저장 비용은 여전히 100MB 이상 절약됩니다.

 

 

4. 알파인은 안전합니다.

 

크기가 훨씬 작은 또 다른 장점은 공격을 받는 표면적이 훨씬 적다는 것입니다.

시스템에 패키지와 라이브러리가 많지 않으면 잘못될 수 있는 일이 거의 없습니다.

몇 년 전에 "ShellShock"이라는 이름으로 공격해 해커가 피해를 입은 경우 컴퓨터에 대한 제어권을 얻을 수 있는 불쾌한 Bash 공격이 있었습니다.

알파인에는 Bash는 기본적으로 설치되지 않기 때문에 해당 공격에서 무사했습니다..

 

또한 대부분의 배포판은 기본적으로 수많은 서비스를 실행합니다. 최신 Debian 또는 Ubuntu 시스템의 ps aux 출력 길이는 1마일이나 됩니다. 이는 Docker가 아닌 설정에서는 합리적일 수 있지만 Dockerized 애플리케이션에는 기본적으로 시작되는 대부분의 작업이 필요하지 않을 가능성이 있습니다.

알파인은 훨씬 다른 접근 방식을 취합니다. 기본적으로 너무 많이 시작하지 않으며 필요한 것만 시작하기를 기대합니다. 이는 Dockerized 애플리케이션에 적합합니다.

 

작업에 가장 적합한 도구를 사용하세요


알파인은 보안 전반에 대해서도 강력한 입장을 취했습니다. 개발팀은 특정 패키지를 보다 안전한 버전으로 교체하는 것을 두려워하지 않습니다. 예를 들어 OpenSSL을 LibreSSL로 대체했습니다.

위에 링크된 페이지에서 이 인용문이 정말 마음에 듭니다.

While OpenSSL is trying to fix the broken code, libressl has simply removed it.

 - OpenSSL이 손상된 코드를 수정하려고 시도하는 동안 libressl은 이를 제거했습니다.

 

제 생각엔 이것이 바로 알파인의 특징이라고 생각합니다. 작고 안전한 Linux 배포판이 되겠다는 약속을 실제로 실천하고 있습니다. 기본 Docker 이미지로 사용될 때 Docker와 함께 사용하기에 완벽한 콤보입니다.

 

 

 

 

 

 

반응형

 

 

 

 

RabbitMQ를 Docker Container로 실행하는 방법에 대해 알아봅니다.

 

 

 

0. 준비사항

 

해당 포스트는 Docker 및 docker-compose를 이용해 RabbitMQ를 실행합니다. Docker와 docker compose를 미리 준비합니다.

 

 

1. docker-compose.yml

 

다음과 같이 docker-compose.yml 파일을 작성합니다.

 

version: '3'
services:
  rabbitmq:
    image: rabbitmq:3.12.4-management-alpine
    container_name: smoh-rabbitmq
    volumes:
      - ./rabbitmq-data/etc/:/etc/rabbitmq/
      - ./rabbitmq-data/data/:/var/lib/rabbitmq/
      - ./rabbitmq-data/logs/:/var/log/rabbitmq/
    ports:
      - "5672:5672"
      - "15672:15672"
    environment:
      RABBITMQ_ERLANG_COOKIE: "RabbitMQ-Cookies"
      RABBITMQ_DEFAULT_USER: "smoh"
      RABBITMQ_DEFAULT_PASS: "password"

 

 

 

2. 컨테이너 실행 및 rabbit management 활성화

 

다음 명령어를 실행해 컨테이너를 실행합니다.

docker-compose up -d

 

 

 

컨테이너가 실행되면 다음 명령어를 통해 bash로 진입합니다.

docker exec -it ##### /bin/bash

 

 

 

bash에서 다음 명령어를 수행해 rabitmq-management를 활성화시켜 줍니다.

rabbitmq-plugins enable rabbitmq_management

 

 

 

 

 

3. 접속 테스트

 

docker-compose에 작성한 WebUI 포트로 접속해 계정 및 암호를 입력한 뒤 Management 페이지를 확인합니다.

 

 

 

정상적으로 동작하는 것을 확인할 수 있습니다.

 

 

 

 

 

 

반응형

+ Recent posts