19.C++ 이외의 프로그래밍 언어에서 사용하기

Edit

ProudNet은 기본적으로 C++ API를 제공합니다. 하지만 다른 프로그래밍 언어를 지속해서 제공할 예정입니다.

팁 : 이종 언어로 된 프로그램간 통신하기

현재는 다음과 같은 언어를 지원합니다.

19.1C# 언어 지원

ProudNet을 C# 에서 사용하는 방법 중 하나는 ProudNet에서 제공하는 C# 래퍼입니다. 물론 4. Remote Method Invocation (원격 메서드 호출)을 위한 PIDL 컴파일러도 C# 언어로 된 proxy와 stub을 생성해줍니다. 따라서 RMI 기능을 포함해서 C# 으로 만들어진 응용 프로그램 개발이 가능합니다.

ProudNet의 C# 래퍼는 소스와 함께 제공됩니다. ProudNet의 C# 래퍼의 빌드 옵션을 원하시는 대로 수정하실 수 있습니다.

ProudNet C# 래퍼는 Visual Studio 2005 및 그 이후 버전과만 호환됩니다.

C# 언어 지원 예제는 11. ProudNet을 C# 에서 사용하는 예제 프로그램에 있습니다.

C# 프로젝트 만들기

C# 응용 프로그램이 ProudNet for C# 을 사용하려면 ProudNet C# 래퍼를 Reference해야 합니다. ProudNet의 C# 래퍼는 ProudNet/srcclr 폴더에 있습니다.

ProudNet/srcclr/client : 클라이언트용 C# 래퍼
ProudNet/srcclr/server : 서버용 C# 래퍼

• 폴더 client는 ProudNet의 클라이언트와 공용 모듈을 포함하고 있으며 폴더 server에는 ProudNet의 서버 모듈을 포함하고 있습니다.

• 폴더 server에는 Proud.CNetServer를 포함하여 서버에만 있으면 되는 모듈들이 들어있습니다. 일반적으로 클라이언트 모듈은 최종 사용자(게임 사용자)에게 배포되지만 서버 모듈은 중요한 개발 자산이므로 배포하는 것은 피해야 합니다. 이러한 점 때문에 서버와 서버와 관련된 모듈은 폴더 server에 별도로 존재합니다.

일반적으로 네트워크 응용 프로그램은 서버 모듈, 클라이언트 모듈, 클라이언트와 서버의 공용 모듈(가령 공통으로 사용하는 구조체 타입 선언 등)으로 구별됩니다. 여기서 공용 모듈과 클라이언트 모듈은 클라이언트용 C# 래퍼를, 서버 모듈은 서버용 클라이언트용 C# 래퍼를 Reference하는 것이 좋습니다.

Reference를 응용 프로그램에 거는 방법은 위 래퍼를 미리 빌드 후 빌드된 DLL 모듈을 거는 방법도 있으며, 래퍼 소스 자체를 Visual Studio 솔루션에 같이 넣어서 소스 프로젝트 자체를 거는 방법이 있습니다. 11. ProudNet을 C# 에서 사용하는 예제 프로그램 후자의 방법을 소개하고 있습니다.

그림 19-1상기 내용과 같이 reference를 건 예입니다.

C# 에서 서버에 연결하기 등 일반적인 사용법

ProudNet C# 래퍼는 네임스페이스 ProudClr 안에 정의되어 있습니다. 그리고 나머지 이름은 ProudNet C++ API의 네임스페이스(Proud) 안에 정의되어 있습니다.

ProudNet C# API는 C++ API와 거의 똑같습니다. 아래는 사용 예입니다. API의 상세한 내용은 상기 ProudNet C# 래퍼 소스에서 확인하십시오. ProudNet C# API를 사용하기 위해서는 C++용 API를 이해해야 합니다. (파트 III. ProudNet 튜토리얼 참고)

using namespace Nettention.ProudClr;

CNetServer server = new CNetServer();

server.AttachStub(C2Sstub);
server.AttachProxy(S2Cproxy);

CStartServerParameter param = new CStartServerParameter();
ProudNetClrTestCommon.Vars vars = new ProudNetClrTestCommon.Vars();
param.m_protocolVersion = Vars.m_Version;
param.m_tcpPort = Vars.m_serverPort;

if (server.Start(param) == false)
Console.WriteLine("Server가 시작실패~!!\n");
else
Console.WriteLine("Server가 시작되었습니다~!!\n");

Nettention.ProudClr.HostID[] list = server.GetClientHostIDs();
groupHostID = server.CreateP2PGroup(list, new Nettention.ProudClr.ByteArray());

C# 에서 사용법이 다른 API

ProudNet의 clr은 C# 문법에 맞게 일부 API가 바뀌었습니다. c++에서 상속을 받아 사용하던 Event(Proud::INetClientEvent 등)가 C# 에서는 delegate를 지원하는 방식입니다. 따라서 모든 가상 함수들을 선언해줄 필요가 없습니다. 또한 SetEventSink(Proud::CNetClient::SetEventSink 등) 함수를 호출하지 않아도 됩니다. 아래는 사용 예입니다.

using Nettention.ProudClr;

public class CClientEventSink
{
    public CClientEventSink(NetClient Client, C2C.Proxy Proxy)
    {
        m_Client = Client;
        m_C2CProxy = Proxy;

        //핸들 넣어주는 곳
        m_Client.JoinServerCompleteHandler = OnJoinServerComplete;
        m_Client.LeaveServerHandler = OnLeaveServer;
        m_Client.P2PMemberJoinHandler = OnP2PMemberJoin;
        m_Client.P2PMemberLeaveHandler = OnP2PMemberLeave;
    }
    public void OnJoinServerComplete(ErrorInfo info, ByteArray replyFromServer)
    {
        // 처리할 로직
    }
    public void OnLeaveServer(ErrorInfo errorInfo)
    {
        // 처리할 로직
    }
    public void OnP2PMemberJoin(HostID memberHostID, HostID groupHostID, int memberCount, ByteArray customField)
    {
        // 처리할 로직
    }
    public void OnP2PMemberLeave(HostID memberHostID, HostID groupHostID, int     memberCount)
    {
        // 처리할 로직
    }
}

C# 에서 PIDL 컴파일러 사용하기

C# 언어에서도 4. Remote Method Invocation (원격 메서드 호출)을 사용할 수 있습니다. 그리고 이를 위해 PIDL compiler도 C# 언어의 proxy와 stub 코드를 생성합니다.

다음과 같이 실행하면 C# 언어의 proxy와 stub 코드가 생성됩니다. (기존 -clr은 -cs와 동일합니다.)

PIDL.exe -cs <input-file-name>

응용 프로그램을 개발하다 보면 서버와 클라이언트가 공통으로 쓰는 모듈이 존재하기 마련입니다. C# 언어로 만들어지는 proxy와 stub은 여기에 들어가는 것이 적당합니다.

그리고 이 모듈에는 11.2 PIDL 컴파일러 실행하기 에서와 마찬가지로 C# 프로젝트에서도 PIDL 파일을 입력받아 커스텀 빌드를 해줄 필요가 있습니다. 이는 다음과 같이 합니다.

그림 19-2C# 프로젝트에서 PIDL 파일을 위한 커스텀 빌드 설정하기

C2S.pidl을 빌드 후 생성되는 proxy,stub은 다음과 같습니다.

C2S_common.cs
C2S_proxy.cs
C2S_stub.cs

이들 파일을 C# 프로젝트(.csproj)에 포함시키십시오. 단, 이들 파일은 빌드 결과물이지, 사용자가 작성하는 순수한 의미의 소스가 아닙니다. 그러므로 소스 컨트롤(가령 SVN 등)에는 넣지 말아야 합니다. 안그러면 읽기전용 파일에 쓰기 오류가 날 수 있습니다.

.csproj 파일을 편집기로 열어 다음과 같이 수정하는 것을 권장합니다.

<Target Name="BeforeBuild">
<ItemGroup>
<Compile Include="C2S_common.cs" />
<Compile Include="C2S_proxy.cs" />
<Compile Include="C2S_stub.cs" />
</ItemGroup>

</Target>
<Target Name="AfterBuild">
</Target>

C# 언어로 생성된 proxy와 stub은 C++에서의 경우와 똑같은 이름의 클래스입니다. (11.3 RMI proxy와 stub을 연결하기 참고) 사용법 또한 C++의 경우와 동일합니다.

자세한 것은 11. ProudNet을 C# 에서 사용하는 예제 프로그램의 Common 모듈 소스를 참고하십시오.

C# 언어에서 사용자 정의 타입을 마샬링하기

RMI의 파라메터에 사용자 정의 객체 타입을 방법은 2. PIDL 파라메터 타입 다루기(마샬링)에 나와있습니다. C# 언어 또한 이것이 가능합니다.

그런데, C++과 달리 C# 은 전역 함수라는 것이 없습니다. 하지만 static 멤버 함수(메서드)라는 것은 허용하고 있습니다. 이러한 점 때문에 PIDL C# 언어에서는 마샬링을 하는 함수들을 갖고 있는 클래스 Nettneion.ProudClr.CMarshaler 가 있습니다.

Nettention.ProudClr.CMarshaler 는 정수,문자열 등 기본 타입을 위한 마샬링 메서드들을 이미 갖고 있습니다. PIDL 컴파일러에 의해 생성되는 proxy와 stub은 Nettention.ProudClr.CMarshaler 의 static 메서드를 사용해서 마샬링을 수행합니다.

사용자 정의 타입을 마샬링하려면 다음을 해야 합니다.

• Nettention.ProudClr.CMarshaler 의 상속 클래스 X를 만들어, 여기에 마샬링을 하는 메서드들을 다음과 같이 추가합니다.

public class X : Nettention.ProudClr.Marshaler
{
    public static bool Read(Nettention.ProudClr.Message msg, out MyClass value)
    {
        value = new MyClass();
        if(msg.Read( out value.a) && msg.Read(out value.b) && msg.Read(out value.c))
            return true;

        return false;
    }

    public static void Write(Nettention.ProudClr.Message msg, MyClass value)
    {
        msg.Write(value.a);
        msg.Write(value.b);
        msg.Write(value.c);
    }
}

• 그리고 PIDL 파일에서는 다음과 같이 상속 클래스 X를 사용하겠다는 선언을 합니다.

[marshaler(cs)=X] global C2C 3000 // marshaler for C#
{
    Foo([in] MyClass a, ...);
}

구현 예는 11. ProudNet을 C# 에서 사용하는 예제 프로그램에 있습니다.

RMI proxy, stub 클래스의 public, internal, private 설정하기

PIDL compiler가 생성하는 proxy, stub, common 클래스의 억세스 한정자는 기본적으로 internal이 설정됩니다. 즉 이들 클래스는 같은 모듈(혹은 어셈블리) 내 다른 소스에서 사용될 수는 있지만 다른 모듈에서는 사용될 수 없습니다.

하지만 이들 클래스들을 모아놓은 모듈을 따로 빌드하고 이 모듈에 있는 이들 클래스들을 다른 모듈에서도 사용하고자 할때는 억세스 한정자를 public으로 바꾸고 싶으실 수 있습니다.

이러한 경우 PIDL compiler가 생성하는 클래스의 억세스 한정자 속성을 다음과 같이 설정하세요.

// This will let proxy, stub and common classes to have access modifier 'public'.
[marshaler(clr)=MyMarshaler, access=public]
global MyC2S 3000
{
    Foo(...);
}

C#, C++ 언어로 된 프로그램간 통신하기

19.2 이종 언어로 된 프로그램간 통신하기를 참고하십시오.

19.2이종 언어로 된 프로그램간 통신하기

두 프로그램이 ProudNet으로 통신하되 서로 다른 프로그래밍 언어로 만들고 싶을 때가 있습니다. 이러한 경우 PIDL compiler는 두 개 이상의 언어로 된 proxy와 stub을 생성한 후 각 프로그램은 필요한 것을 가져다 쓰면 됩니다.

int, double, string 등 기본 타입에 대해서는 ProudNet의 C++ 외의 언어를 위한 래핑 모듈에서 이미 제공하고 있습니다. 하지만 언어가 서로 다르면 이러한 기본 타입의 이름이 기본적으로 달라지기 마련입니다. 예를 들어 C# 은 문자열 클래스가 System.String 인데, C++에서는 std::string , std::wstring, ATL::CString , Proud::String입니다.

이를 해결하기 위해 PIDL compiler는 사용자가 원할 경우 생성되는 proxy,stub에서 변수 타입을 특정 언어에 한해서 변경하는 기능을 제공하고 있습니다. 아래는 사용 예입니다.

// C# 언어의 proxy,stub 생성시 TypeA를 TypeB로 개명합니다.
rename cs(TypeA,TypeB);
// C++ 언어의 proxy,stub 생성시 TypeC를 TypeD로 개명합니다.
rename cpp(TypeC,TypeD);

global XXX 2000
{
    Foo([in]TypeA a);  // C# 언어로 proxy,stub 생성시 Foo(TypeB a) 가 됩니다,
    Goo([in]TypeC c);  // C++ 언어로 proxy,stub 생성시 Goo(TypeD c) 가 됩니다.
}