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

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

C++ 쪽에서의 CFastArray를 serializing해서 보냈을 때에 C# 쪽에서 이를 받아 deserializing하여 사용하는 방법을 예로 들어서 설명해드리도록 하겠습니다.

설명은 아래에 나와있는 5 단계로 진행됩니다.

  1. C# Student 클래스 작성

  2. C++ CStudent 클래스 작성

  3. PIDL 작성

  4. C++ 마샬링 코드 작성

  5. C# 마샬링 코드 작성

본 설명에서 작성해보는 간략한 예제는 C# 클라이언트에서 Ping 라는 RMI를 호출하면, 그것을 받은 C++ 서버는 StudentList RMI를 호출하여 C++의 CFastArray를 C# 쪽으로 전달하게 되고, C# 쪽은 그것을 List로 전달받는 예제입니다.

18.1C# Student 클래스

namespace CsClient
{
    class Student
    {
        public string Name;
        public int ID;
        public int Kor;
        public int Eng;
        public int Mat;
        public override string ToString()
        {
            return string.Format("Name: {0}({1}) K: {2}, E: {3}, M: {4}", Name, ID, Kor, Eng, Mat);
        }
    }
} 

C#쪽 클라이언트에서 사용될 클래스입니다.

18.2C++ CStudent 클래스 작성

class CStudent
{
    public:
    String Name;
    int ID;
    int Kor;
    int Eng;
    int Mat;
}; 

C++쪽 서버에서 사용될 클래스입니다.

18.3PIDL 작성

rename cs(Proud::CFastArray<CStudent>, System.Collections.Generic.List<CsClient.Student>);
[marshaler(cs)=CsClient.MyMarshaler]
global S2C 3000
{
    StudentList([in] Proud::CFastArray<CStudent> students);
} 

C2S.PIDL

[marshaler(cs)=CsClient.MyMarshaler]
global C2S 4000
{
    Ping([in] int value);
} 

이 예제 PIDL 코드는 클라이언트에서 Ping을 보내면 StudentList를 보내주는 PIDL 코드입니다.

해당 파일을 빌드하셔서 .h, .cpp, .cs 파일을 생성합니다.

18.4C++ 마샬링 코드 작성

namespace Proud
{
    CMessage& operator >> (CMessage& msg, CStudent student)
    {
        msg >> student.Name >> student.ID >> student.Kor >> student.Eng >> student.Mat;
        return msg;
    }
    CMessage& operator << (CMessage& msg, const CStudent& student)
    {
        msg << student.Name << student.ID << student.Kor << student.Eng << student.Mat;
        return msg;
    }
} 

예제로 만들어진 CStudent클래스를 마샬링하는 코드입니다.

더 자세한 정보는 http://guide.nettention.com/cpp_ko#collection_marshal 링크를 참조해 주십시오.

C2SStub

class C2SStub : public C2S::Stub
{
    public:
    DECRMI_C2S_Ping;
};

DEFRMI_C2S_Ping(C2SStub)
{
    {
        CriticalSectionLock(g_lock, true);
        g_S2CProxy.StudentList(remote, RmiContext::ReliableSend, g_Students);
    }
    return true;
}
C2SStub g_C2SStub; 

C# 클라이언트에서 Ping을 보내오면 StudentList를 보내주는 코드입니다.

18.5C# 마샬링 코드 작성

namespace CsClient
{
    class MyMarshaler : Nettention.Proud.Marshaler
    {
        public static bool Read(Message msg, out List<Student> students)
        {
            students = null;
            if (!msg.ReadScalar(out var size))
            {
                return false;
            }
            students = new List<Student>();
            for (int i = 0; i < size; ++i)
            {
                Student s = new Student();
                if (!msg.Read(out s.Name)) { return false;
                }
                if (!msg.Read(out s.ID))
                {
                    return false;
                }
                if (!msg.Read(out s.Kor))
                {
                    return false;
                }
                if (!msg.Read(out s.Eng))
                {
                    return false;
                }
                if (!msg.Read(out s.Mat))
                {
                    return false;
                }
                students.Add(s);
            }
            return true;
        }

        public static void Write(Message msg, List<Student> students)
        {
            msg.WriteScalar(students.Count);
            for (int i = 0; i < students.Count; ++i)
            {
                msg.Write(students[i].Name);
                msg.Write(students[i].ID);
                msg.Write(students[i].Kor);
                msg.Write(students[i].Eng);
                msg.Write(students[i].Mat);
            }
        }
    }
} 

C#의 마샬링은 Nettention.Proud.Marshaler을 상속받아 구현한 뒤, 대체하는 방식으로 개발됩니다.

대체는 직접 하실 필요없이 PIDL에 선언한 [marshaler(cs)=CsClient.MyMarshaler] 키워드로 동작합니다.

g_S2CStub.StudentList = (remote, rmiContext, students) =>
{
    lock(g_lock)
    {
        // List<Student> 로 넘어오는 students를 사용하시면 됩니다.
        foreach (var s in students)
        {
            Console.WriteLine(s.ToString());
        }
    }
    return true;
};