42. 프로그래밍 Part 3: 프로그램 실행 인자

iFun Engine 에서는 프로그램의 설정 내용은 MANIFEST.json 로 관리됩니다.

그러므로, 실행 인자를 전달하는 방법은 크게 MANIFEST.json 에 인자를 지정하는 방법과, 명령행 인자를 추가하는 방법이 있습니다.

42.1. 방법1: MANIFEST.json 을 이용

42.1.1. MANIFEST.json 에 인자 추가하기

아래처럼 MANIFEST.json 에 arguments 라는 JSON property 를 추가하고 그 안에 사용할 인자들을 정의합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "version": 1,

  "components": [
    {
      "name": "MyProjectServer",

      "arguments": {
        "example_arg1": "val1",
        "example_arg2": 100
      },

      "library": "libmy_project.so",

      "dependency": {

        ...

        "SessionService": {
          "tcp_json_port": 8012,
          ...
        },

        ...
      }
    }
  ]
}

42.1.2. 서버 코드에서 인자 읽기

MANIFEST.json 에 추가된 인자들은 해당 서버의 Install 함수가 호출될 때 전달 됩니다. 아래는 위의 MANIFEST.json 을 읽는 경우입니다.

my_project_server.cc:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MyProjectServer : public Component {
 public:
  static bool Install(const ArgumentMap &arguments) {
    LOG(INFO) << "Built using Engine version: " << FUNAPI_BUILD_IDENTIFIER;

    // Kickstarts the Engine's ORM.
    // Do not touch this, unless you fully understand what you are doing.
    my_project::ObjectModelInit();

    /*
     * Parameters specified in the "arguments" section in your MANIFEST.json
     * will be passed in the variable "arguments".
     * So, you can give configuration data to your game server.
     *
     * Example:
     *
     * We have in MANIFEST.json "example_arg1" and "example_arg2" that
     * have a string value and an integer value, respectively.
     * So, you can access the arguments like below:
     */
    string arg1 = arguments.FindStringArgument("example_arg1");
    LOG(INFO) << "example_arg1: " << arg1;

    int64_t arg2 = arguments.FindIntegerArgument("example_arg2");
    LOG(INFO) << "example_arg2: " << arg2;

     // You can override gflag like this: ./my_project-local --example_arg3=hahaha
    LOG(INFO) << "example_arg3: " << FLAGS_example_arg3;


    /*
     * Registers various handlers.
     * You may be interesed in this function and handlers in it.
     * Please see "event_handlers.cc"
     */
    my_project::RegisterEventHandlers();

    return true;
  }
}

server.cs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
namespace MyProject
{
  public class Server
  {
    public static void Install(ArgumentMap arguments)
    {
      // Session open, close handlers.
      NetworkHandlerRegistry.RegisterSessionHandler (
        new NetworkHandlerRegistry.SessionOpenedHandler (OnSessionOpened),
        new NetworkHandlerRegistry.SessionClosedHandler (OnSessionClosed));

      // "echo" message handler for JSON type.
      NetworkHandlerRegistry.RegisterMessageHandler ("echo", new NetworkHandlerRegistry.JsonMessageHandler (OnEcho));

      // "echo_pbuf" message handler for Google Protocol Buffers.
      NetworkHandlerRegistry.RegisterMessageHandler ("echo_pbuf", new NetworkHandlerRegistry.ProtobufMessageHandler (OnEchoPbuf));

      // Parameters specified in the "arguments" section in your MANIFEST.json
      // will be passed in the variable "arguments".
      // So, you can give configuration data to your game server.
      //
      // Example:
      //
      // We have in MANIFEST.json "example_arg1" and "example_arg2" that
      // have a string value and an integer value, respectively.
      // So, you can access the arguments like below:
      string arg1 = arguments.FindString ("example_arg1");
      Log.Info ("example_arg1: {0}", arg1);

      Int64 arg2 = arguments.FindInteger ("example_arg2");
      Log.Info ("example_arg2: {0}", arg2);

      // You can override gflag like this: ./mono-local --example_arg3=hahaha
      Log.Info("example_arg3: {0}", Flags.GetString ("example_arg3"));

      // Registers a timer.
      //
      // Below demonstrates a repeating timer. One-shot timer is also available.
      // Please see the Timer class.
      Timer.ExpireRepeatedly(WallClock.FromSec(1), OnTick);
    }
  }
}

42.2. 방법2: Google Flag 로 추가

42.2.1. Google flag 추가하기

먼저 사용할 실행 인자를 Google Gflag 를 이용해서 코드 상에서 정의합니다.

이 때 사용되는 함수들은 다음과 같습니다.

DEFINE_bool boolean
DEFINE_int32 32-bit integer
DEFINE_int64 64-bit integer
DEFINE_uint64 unsigned 64-bit integer
DEFINE_double double
DEFINE_string C++ string

예를 들면 아래와 같습니다.

DEFINE_string(my_arg1, "기본값", "my_arg1에 대한 설명");

Note

C# 의 경우 mono/server.cs 가 아닌 src/{{project_name}}_server.cc 에 C++ 코드로 추가하셔야 됩니다.

42.2.2. 서버 코드에서 flag 읽기

해당 flag 가 필요한 경우 DEFINE_XYZ() 와 매칭되는 DECLARE_XYZ() 라는 함수로 flag 를 선언 하고 코드 상에서 FLAGS_XYZ 라는 이름으로 사용하면 됩니다.

사용 가능한 DECLARE_XYZ() 함수들은 다음과 같습니다.

DECLARE_bool boolean
DECLARE_int32 32-bit integer
DECLARE_int64 64-bit integer
DECLARE_uint64 unsigned 64-bit integer
DECLARE_double double
DECLARE_string C++ string

my_project_server.cc:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// You can differentiate game server flavors.
DECLARE_string(example_arg3);

class MyProjectServer : public Component {
 public:
  static bool Install(const ArgumentMap &arguments) {
    LOG(INFO) << "Built using Engine version: " << FUNAPI_BUILD_IDENTIFIER;

    // Kickstarts the Engine's ORM.
    // Do not touch this, unless you fully understand what you are doing.
    my_project::ObjectModelInit();

    /*
     * Parameters specified in the "arguments" section in your MANIFEST.json
     * will be passed in the variable "arguments".
     * So, you can give configuration data to your game server.
     *
     * Example:
     *
     * We have in MANIFEST.json "example_arg1" and "example_arg2" that
     * have a string value and an integer value, respectively.
     * So, you can access the arguments like below:
     */
    string arg1 = arguments.FindStringArgument("example_arg1");
    LOG(INFO) << "example_arg1: " << arg1;

    int64_t arg2 = arguments.FindIntegerArgument("example_arg2");
    LOG(INFO) << "example_arg2: " << arg2;

     // You can override gflag like this: ./my_project-local --example_arg3=hahaha
    LOG(INFO) << "example_arg3: " << FLAGS_example_arg3;


    /*
     * Registers various handlers.
     * You may be interesed in this function and handlers in it.
     * Please see "event_handlers.cc"
     */
    my_project::RegisterEventHandlers();

    return true;
  }
}

해당 flag 가 필요한 경우 Flags.GetString(“XYZ”) 형태로 값을 읽을 수 있습니다.

이 때 타입 별로 Get 할 수 있는 함수들은 다음과 같습니다.

GetBool boolean
GetInt32 32-bit integer
GetInt64 64-bit integer
GetUInt64 unsigned 64-bit integer
GetDouble double
GetString C# string

server.cs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
namespace MyProject
{
  public class Server
  {
    public static void Install(ArgumentMap arguments)
    {
      // Session open, close handlers.
      NetworkHandlerRegistry.RegisterSessionHandler (
        new NetworkHandlerRegistry.SessionOpenedHandler (OnSessionOpened),
        new NetworkHandlerRegistry.SessionClosedHandler (OnSessionClosed));

      // "echo" message handler for JSON type.
      NetworkHandlerRegistry.RegisterMessageHandler ("echo", new NetworkHandlerRegistry.JsonMessageHandler (OnEcho));

      // "echo_pbuf" message handler for Google Protocol Buffers.
      NetworkHandlerRegistry.RegisterMessageHandler ("echo_pbuf", new NetworkHandlerRegistry.ProtobufMessageHandler (OnEchoPbuf));

      // Parameters specified in the "arguments" section in your MANIFEST.json
      // will be passed in the variable "arguments".
      // So, you can give configuration data to your game server.
      //
      // Example:
      //
      // We have in MANIFEST.json "example_arg1" and "example_arg2" that
      // have a string value and an integer value, respectively.
      // So, you can access the arguments like below:
      string arg1 = arguments.FindString ("example_arg1");
      Log.Info ("example_arg1: {0}", arg1);

      Int64 arg2 = arguments.FindInteger ("example_arg2");
      Log.Info ("example_arg2: {0}", arg2);

      // You can override gflag like this: ./mono-local --example_arg3=hahaha
      Log.Info("example_arg3: {0}", Flags.GetString ("example_arg3"));

      // Registers a timer.
      //
      // Below demonstrates a repeating timer. One-shot timer is also available.
      // Please see the Timer class.
      Timer.ExpireRepeatedly(WallClock.FromSec(1), OnTick);
    }
  }
}

42.2.3. 명령행 실행 시 인자 전달하기

이제 게임 서버는 --example_arg3 이라는 실행 인자를 인식하게 됩니다. 즉, --example_arg3=my_value 형태로 사용하게 됩니다.

$ ./my_game_server-local --example_arg3=my_value

혹은 EXTRA_ARGS 라는 환경 변수에 추가할 인자들을 모두 나열하셔도 됩니다.

$ EXTRA_ARGS="--my_arg1=my_value" ./my_game_server-local

또는

$ export EXTRA_ARGS="--my_arg1=my_value"
$ ./my_game_server-local

42.2.4. 서비스로 실행시 인자 전달하기

게임 서버를 패키징해서 서비스로 실행하는 경우는 앞에서와 같이 실행 인자를 넘겨주는 것이 불가능합니다. 그 경우는 서비스 설정하기 에 언급된 파일들에 실행 인자를 정의해서 넘겨줄 수 있습니다.

Upstart:

etc/upstart/default/{{project-name}} 파일에 export EXTRA_ARGS="--example_arg3=my_value --example_arg4=another" 형태로 입력합니다.

Important

export 를 반드시 붙여야되며, EXTRA_ARGS 뒤에 나오는 = 은 앞뒤로 공백없이 붙여써야 됩니다.

Systemd:

etc/systemd/{{project-name}}EXTRA_ARGS="--example_arg3=my_value --example_arg4=another" 형태로 입력합니다.

Important

export 없이 작성하셔야 됩니다.