환영
원격(Remoting) 튜토리얼에 오신 것을 환영한다. 이 튜토리얼은 원격으로 원격 서비스를 구현하기 위해 필요한 기본 개념과 기술에 익숙해 지도록 하는 것이다. 튜토리얼의 파트 1은 원격 기초를 다룬다. 파트 2에서는 향상된 원격 프로그래밍 개념을 살펴볼 것이다.
이 튜토리얼은 기초적인 POCO C++ 라이브러리 프로그래밍 기술에 익숙하다고 가정한다. 당신은 또한 원격 개요를 읽어보고 기초적인 원격 개념에 익숙해 져야 한다.
노트: 이 튜토리얼은 원격 프레임웍의 macchina.io 오픈 소스 릴리즈에서 이용가능한 특징들 만을 다룬다. 상업 버전(SOAP, JSON-RPC와 REST 전송)에서 이용가능한 특징은 다루지 않는다.
서비스 클래스 작성하기
원격 서비스를 생성하는 첫번째 단계는 실제 원격 서비스를 구현하는 클래스인 서비스 클래스를 설계하고 구현하는 것이다. 예를 들어, 우리는 단지 현재의 시간을 리포트하는 간단한 서비스를 구현할 것이다. 시작 단계를 간단하게 유지하기 위해서, 시간은 HH:MM:SS(시, 분, 초) 형태의 문자열로 리턴할 것이다. 나중에 우리는 어떻게 다른 데이터 타입(사용자 정의 타입조차)을 사용한 다른 형태의 시간을 리턴할지 보게될 것이다.
그러면, 클래스 정의와 함께 시작해 보자:
class TimeService
{
public:
TimeService();
~TimeService();
std::string currentTimeAsString() const;
};
지금까지 우리의 클래스는 어떤 다른 평범한 C++ 클래스와 같이 보였다. 이 클래스를 원격 서비스로 전환하기 위해서, 우리는 @remote 속성, 클래스중 하나인, 또는 currentTimeAsString() 멤버 함수로 추가 해야 한다(?). 클래스를 위한 컴파일 헤더 파일(TimeService.h)은 아래에 제시되어있다. @remote 속성은 클래스 레벨(이것은 클래스의 모든 멤버 함수가 원격으로 이용가능하다는 것을 의미한다)에서 추가되었다.
#ifndef TimeService_INCLUDED
#define TimeService_INCLUDED
#include <string>
namespace Sample {
//@ remote
class TimeService
{
public:
TimeService();
/// Creates the TimeService.
~TimeService();
/// Destroys the TimeService.
std::string currentTimeAsString() const;
/// Returns the current time, formatted
/// as a string (HH:MM::SS).
};
} // namespace Sample
#endif // TimeService_INCLUDED
클래스의 실제 구현은 간단하다. 우리는 간단하게 현재 시간(과 날짜)를 얻기위해서 Poco::DateTime 클래스를 사용하고 시간을 문자열로 포맷팅하기 위해서 Poco::DateTimeFormatter를 사용한다.
#include "TimeService.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormatter.h"
namespace Sample {
TimeService::TimeService()
{
}
TimeService::~TimeService()
{
}
std::string TimeService::currentTimeAsString() const
{
Poco::DateTime now;
return Poco::DateTimeFormatter::format(now, "%H:%M:%S);
}
} // namespace Sample
서버 코드 생성하기
서비스 클래스를 작성한 다음, 다음 단계는 서비스 클래스 상에서 RemotingNG 코드 생성기 (RemoteGenNG)를 구동하는 것이다. 코드 생성기를 구동하기 위해서, 코드 생성기를 위한 구성구성 파일은 파일이 먼저 만들어 져야 한다. 코드가 생성되어지는 것만큼 잘 코드를 생성하기 위한 클래스들인 코드 생성기를 말한다(?). 코드 생성기는 각 헤더 파일을 파싱하기 전에 C++ 컴파일러의 전처리기를 호출하기 위해 필요하다. 그래서, 구성 파일은 또한 어떻게 전처리기를 호출하는지에 대한 정보를 포함한다. 구성 파일은 XML 형식을 사용한다.
코드 생성기 구성하기
다음의 구성 파일은 우리의 TimeService 원격 서비스를 위한 서버 코드를 만들기 위해 코드 생성기를 구성한다. 이것은 Visual C++ 컴파일러로 부터의 전처리기를 사용한다.
<AppConfig>
<RemoteGen>
<files>
<include>
${POCO_BASE}/RemotingNG/include/Poco/RemotingNG/RemoteObject.h
${POCO_BASE}/RemotingNG/include/Poco/RemotingNG/Proxy.h
${POCO_BASE}/RemotingNG/include/Poco/RemotingNG/Skeleton.h
include/TimeService.h
</include>
</files>
<output>
<mode>server</mode>
<include>include</include>
<src>src</src>
<namespace>Sample</namespace>
<copyright>Copyright (c) 2012</copyright>
</output>
<compiler>
<exec>cl</exec>
<options>
/I "${POCO_BASE}/RemotingNG\Foundation\include"
/I "${POCO_BASE}/RemotingNG\RemotingNG\include"
/nologo
/C
/P
/TP
</options>
</compiler>
</RemoteGen>
</AppConfig>
다음은 구성 파일에서 는 XML 원소의 간략한 토론이다(?)
AppConfig
The name of the root element is actually not relevant. We have chosen AppConfig, but any other valid element name would do as well.
RemoteGen
This element is required. Its child elements contain the configuration data for the code generator.
files/include
The content of this element is a list of paths (or Glob expressions, exactly) that tell the code generator which header files to parse. The paths specified here can be relative (as in the example) or absolute. Paths must be separated by either a newline, a comma or a semicolon. We have used the configuration variable ${POCO_BASE} to specify the path to the POCO base directory. For this to work, a value for that variable must be passed to the code generator when invoking it.
There are three header files that always must be specified here. These are Poco/RemotingNG/RemoteObject.h, Poco/RemotingNG/Proxy.h and Poco/RemotingNG/Skeleton.h. Failing to include these files will result in the code generator reporting an error. If events are used, the header files Poco/RemotingNG/EventDispatcher.h and Poco/RemotingNG/EventSubscriber.h must be included as well.
output/mode
This specifies what code the generator should generate. For server code, we specify "server". Other valid values would be "client", "both" (generates both client and server code) and "interface" (generates only the interface class).
output/include
This specifies the directory where generated header files are written to.
output/src
This specifies the directory where generated implementation files are written to.
output/namespace
This specifies the C++ namespace, where generated classes will be in.
output/copyright
This specifies a copyright (or other) message that will be added to the header comment section of each generated file.
compiler/exec
This specifies the name of the C++ compiler executable to use. In the above example, we use the Visual C++ compiler.
compiler/options
This specifies the command line options passed to the compiler. The options should direct the compiler to simply run the preprocessor, and write the preprocessed output to a file named header.i in the current directory. This file is then parsed by the code generator. Options must be separated with either a newline, a comma or a semicolon.
In the above example, the command line options have the following meaning:
/I: specify search path for include files.
/nologo: do not display the startup banner.
/C: preserve comments during preprocessing (important, otherwise the code generator would not see the attributes).
/P: preprocess to a file.
/TP: assume a C++ header file.
GCC를 위한 코드 생성기 구성하기
GCC를 사용하는 리눅스 또는 유닉스 플랫폼에서 코드 생성기를 실행하기 위해서, 구성 파일의 컴파일러 섹션은 다음과 같이 변경되어야 한다:
<exec>g++</exec>
<options>
-I${POCO_BASE}/RemotingNG/Foundation/include
-I${POCO_BASE}/RemotingNG/Remoting/include
-I./include
-E
-C
-o%.i
</options>
다음의 옵션들은 컴파일러에게 넘겨진다:
-I: specify search path for include files.
-E: run the preprocessor only.
-C: preserve comments during preprocessing (important, otherwise the code generator would not see the attributes).
-o: specify the file where preprocessor output is written to.
멀티플 컴파일러를 위한 코드 생성기 구성하기
원격 NG로 구성 파일에서 멀티플 컴파일러를 갖는 것이 가능하다(?). 이 경우, 모든 컴파일러 element는 element를 구분하는 이름으로 id 속성을 가져야 한다. 코드 생성기를 호출할 때, 컴파일러는 명령어 라인에 명시될 수 있다. 이것은 멀티플 플랫폼에서 같은 구성 파일을 사용하는 것이 가능하도록 해준다. 다음의 예에서, GCC, Clang 그리고 비쥬얼 C++을 위한 컴파일러 정의가 제공된다:
<compiler id="gcc">
<exec>g++</exec>
<options>
-I${POCO_BASE}/RemotingNG/Foundation/include
-I${POCO_BASE}/RemotingNG/include
-I./include
-E
-C
-o%.i
</options>
</compiler>
<compiler id="clang">
<exec>clang++</exec>
<options>
-I${POCO_BASE}/Foundation/include
-I${POCO_BASE}/RemotingNG/include
-I./include
-E
-C
-xc++
-o%.i
</options>
</compiler>
<compiler id="msvc">
<exec>cl</exec>
<options>
/I "${POCO_BASE}\Foundation\include"
/I "${POCO_BASE}\RemotingNG\include"
/nologo
/C
/P
/T
</options>
</compiler>
코드 생성기 호출하기
RemoteGen 실행파일과 C++ 컴파일러 모두가 실행 검색 경로(%PATH% 또는 $PATH)에 있다고 가정하고, 구성 파일이 TimerServer.xml이라는 이름을 갖으면, 당신은 윈도우 쉘에서 아래와 같이 코드 생성기를 시작할 수 있다:
RemoteGenNG TimeServer.xml /D:POCO_BASE=c:\poco
유닉스 쉘에는 다음과 같다:
RemoteGenNG TimeServer.xml -DPOCO_BASE=/path/to/poco
동작하기 위해서 이 경우, 우리는 우리의 소스와 헤더 파일이 다음과 같은 디렉토리 구성이라고 가정한다:
TimeServer/
include/
TimeService.h
src/
TimeService.cpp
TimeServer.xml
코드 생성기가 시작될 때 현재의 작업 디렉토리는 TimerServer 디렉토리이러야 한다.
코드 생성기는 전처리기, 전처리된 헤더 파일을 파싱하고 코드를 생성하기 위해서 수초가 걸린다. 코드 생성기가 이러한 작업을 마치고, 다음의 소스와 헤더 파일은 우리의 프로젝트 디렉토리에서 찾을 수 있다:
TimeServer/
include/
TimeService.h
ITimeService.h
TimeServiceRemoteObject.h
TimeServiceSkeleton.h
TimeServiceServerHelper.h
src/
TimeService.cpp
ITimeService.cpp
TimeServiceRemoteObject.cpp
TimeServiceSkeleton.cpp
TimeServiceServerHelper.cpp
TimeServer.xml
파일명에서 볼 수 있듯이, 코드 생성기는 다음의 클래스들을 생성한다:
the interface class (ITimeService),
the remote object class (TimeServiceRemoteObject),
the server skeleton class (TimeServiceSkeleton),
and the server helper class (TimeServiceServerHelper).
서버에서 우리에게 가장 중요한 클래스는 서버 헬퍼 클래스이다. 이 클래스는 원격으로 사용할 수 있는 우리의 서비스 객체를 만들기 위해 필요한 작업의 대다수를 수행한다.
서버 어플리케이션 작성하기
.
.
.
클라이언트 코드 작성하기
코드 생성기 구성하기
코드 생성기 호출하기
클라이언트 어플리케이션 작성하기