C# ↔ C++의 이기종 통신을 위한 마샬링에 대해서 살펴보겠습니다. 여기서 언급되는 컨셉은 JAVA ↔ C# , JAVA ↔ C++ 등으로 확장될수도 있습니다. |
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);
}
} |
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();
}
} |