C# ↔ C++의 이기종 통신을 위한 마샬링에 대해서 살펴보겠습니다.

여기서 언급되는 컨셉은 JAVA ↔ C# , JAVA ↔ C++ 등으로 확장될수도 있습니다.




C# Base Class
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices; //관리되지않는 코드 (포인터 사용및 구조체를 시퀜셜하게 만들기위해)
using System.Web.Script.Serialization;
 
[StructLayout(LayoutKind.Sequential, Pack = 1)] // #pragma pack(1) 과 동일한 효과..
    public class ConvertPacket
    {
        // 받은 패킷 바이트를 구조체화함
        public void SetBuffer(byte[] pbyte)
        {
            unsafe	// c#에서는 포인터연산을 통한 메모리복사를 안전하지 않는 코드로 판단, unsafe블록안에 감싸줘야함
            {
                try
                {                    
                    fixed (byte* fixed_buffer = pbyte)
                    {
                        Marshal.PtrToStructure((IntPtr)fixed_buffer, this);                       
                    }                    
                }
                catch (Exception e)
                {                    
                    LogUtil.Instance.writeLog(LOGLEVELTYPE.WARN, "SYSTEM", "LSSOCK", string.Format("ParserError {0} - {1}", e.Message, e.Source) , "ConvertPacket::SetBuffer");
                }
            }
        }
 
        // 보낼패킷 구조체를 byte에 복사함
        public void PutBuffer(byte[] pbyte)
        {
            int mycount = Marshal.SizeOf(this);
 
            unsafe
            {
                fixed (byte* fixed_buffer = pbyte)
                {
                    Marshal.StructureToPtr(this, (IntPtr)fixed_buffer, true);                    
                    for (int i = 0; i < mycount; i++)
                    {
                        pbyte[i] = fixed_buffer[i];
                    }
                }
            }
        }
 
        public int GetSize()
        {
            return Marshal.SizeOf(this);
        }
 
        public byte[] GetBuffer()
        {
            byte[] resultObj = new byte[ GetSize() ];
            PutBuffer( resultObj );
            return resultObj;
        }
 
        public override string ToString()  //이것은 디버깅을위해 패킷을 까보는 활동의 코드입니다.
        {
            return new JavaScriptSerializer().Serialize(this);
        }
    }



사용예 C++로 데이터전송
using System.Runtime.InteropServices; //관리되지않는 코드 (포인터 사용및 구조체를 시퀜셜하게 만들기위해)
using System.Text; //문자열을 byte[]배열에 넣기 위해
using System.Net.Sockets; //소켓 통신을위해
using System.Diagnostics;  //디버깅을 위해
 
// 클래스(구조체) 샘플.
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public class CK_KEEPALIVE : ConvertPacket
    {
        public char cRes;
        public int nRes;
        public CK_KEEPALIVE()
        {
        }
    }
 
public class Sample
{
    public void Text()
    {
        CK_KEEPALIVE tmpPacket = new CK_KEEPALIVE();
 
        tmpPacket.nRes = 1234;  //원하는 값을 채운다.
 
 
        //소켓연결        
        TcpClient tcpClient = new TcpClient();
        tcpClient.Connect("localhost", 8296);
 
        NetworkStream networkStream = tcpClient.GetStream();
 
        //보내기
        networkStream.Write(tmpPacket.GetBuffer(), 0, tmpPacket.GetSize() );
 
        //받기
        CK_KEEPALIVE tmpPacket2 = new CK_KEEPALIVE();
 
        byte[] buffer = new byte[ tmpPacket.GetSize() ];
 
        networkStream.Read(buffer, 0, tmpPacket.GetSize() );
 
        tmpPacket.SetBuffer(buffer);  //받은 바이너리 패킷을 구조체에 적용함
 
        networkStream.Close();
        tcpClient.Close();
    }
}
  • No labels