=================================
=================================
=================================
출처: https://jacking.tistory.com/112
C#으로 클라이언트나 서버를 만들 때 C++에 비해서 가장 아쉬운 것이 클래스(혹은 구조체)를 byte[](C++로 보면 char* 입니다)로 바로 변환하지 못 한다는 것입니다. 클래스를 바로 byte[]로 변환만 할 수 있으면(혹은 반대로) 네트웍으로 받은 데이터를 처리하는 것이 간단해지는데 C#으로는 그것이 쉽지 않아서 좀 피곤하기도 합니다.처음에는 어떻게든 변환 해보려고 했는데 막상 해보니 이것도 나름 피곤하고 성능 상으로 좋지도 않아서 지금은 이 방법은 사용하지 않습니다. 아래는 클래스를 byte[]로 변환하는 코드입니다.이 방법은 데브피아에서 찾았습니다.
// 패킷 헤더 클래스
[StructLayout(LayoutKind.Sequential)]//[StructLayout(LayoutKind.Sequential, Pack=1)]
public class HEADER
{
public ushort a1;
public ushort a2;
public ushort a3;
public ushort a4;
}
// 로그인 요청 클래스
// GetBuffer을 부모 클래스에서 정의하고 여기서는 상속 받지 않은 이유는 그렇게 하면 클래스의
// 데이타를 복사 할 때 부모클래스의 크기(4바이트) 만큼을 앞에 계산 해버린다
[StructLayout(LayoutKind.Sequential)]
public class LoginAuthorRet
{
public LoginAuthorRet()
{
Header = new HEADER();
acID = new byte[21];
acPasswd = new byte[31];
}
// 클래스의 있는 데이타를 메모리에 담아서 리턴 한다.
public void GetBuffer( byte[] outBuffer )
{
if( 0 == outBuffer.Length )
outBuffer = new byte[ MAX_PACKET_DATA ];
unsafe
{
fixed(byte* fixed_buffer = outBuffer)
{
Marshal.StructureToPtr(this, (IntPtr)fixed_buffer, false);
}
}
}
public HEADER Header; // 헤더
[MarshalAs(UnmanagedType.ByValArray, SizeConst=21)] public byte[] acID; // 아이디
[MarshalAs(UnmanagedType.ByValArray, SizeConst=31)] public byte[] acPasswd; // 패스워드
}
사용 예
LoginAuthorRet LoginPacket = new LoginAuthorRet();링크
LoginPacket.Header.a2 = PK_LOGIN_AUTHOR_REQ;
LoginPacket.Header.a3 = (ushort)(Marshal.SizeOf(LoginPacket)-Marshal.SizeOf(LoginPacket.Header));
int iIDLen = strID.Length;
int iPWLen = strPass.Length;
Buffer.BlockCopy( Encoding.ASCII.GetBytes(strID), 0, LoginPacket.acID, 0, iIDLen );
Buffer.BlockCopy( Encoding.ASCII.GetBytes(strPass ), 0, LoginPacket.acPasswd, 0, iPWLen );byte[] packet1 = new byte[ MAX_PACKET_DATA ];
LoginPacket.GetBuffer( packet1 );
SendPacket( packet1, Marshal.SizeOf(LoginPacket) );
2. byte[] to struct
출처: http://qiita.com/maenotti_99/items/519047bee9fd19e6cb10
구조체
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct Hoge
{
/// <summary> 6:コード</summary>
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 6 )]
public byte[] Code;
}
변환 함수
static public object ToStr( byte[] byteData, Type type )
{
GCHandle gch = GCHandle.Alloc( byteData, GCHandleType.Pinned );
object result = Marshal.PtrToStructure( gch.AddrOfPinnedObject(), type );
gch.Free();
return result;
}
사용 방법
Hoge dataL = (Hoge)ToStr( byData, typeof( Hoge ) );
3. struct to byte[]
출처: http://qiita.com/yu_ka1984/items/969728290b05e15f07a9
public static byte[] ToByteArray<T>(this T structure) where T : struct
{
byte[] bb = new byte[Marshal.SizeOf(typeof(T))];
GCHandle gch = GCHandle.Alloc(bb, GCHandleType.Pinned);
Marshal.StructureToPtr(structure, gch.AddrOfPinnedObject(), false);
gch.Free();
return bb;
}
=================================
=================================
=================================
//byte 배열을 구조체로
public static object ByteToStructure(byte[] data, Type type)
{
IntPtr buff = Marshal.AllocHGlobal(data.Length); // 배열의 크기만큼 비관리 메모리 영역에 메모리를 할당한다.
Marshal.Copy(data, 0, buff, data.Length); // 배열에 저장된 데이터를 위에서 할당한 메모리 영역에 복사한다.
object obj = Marshal.PtrToStructure(buff, type); // 복사된 데이터를 구조체 객체로 변환한다.
Marshal.FreeHGlobal(buff); // 비관리 메모리 영역에 할당했던 메모리를 해제함
if (Marshal.SizeOf(obj) != data.Length)// (((PACKET_DATA)obj).TotalBytes != data.Length) // 구조체와 원래의 데이터의 크기 비교
{
return null; // 크기가 다르면 null 리턴
}
return obj; // 구조체 리턴
}
// 구조체를 byte 배열로
public static byte[] StructureToByte(object obj)
{
int datasize = Marshal.SizeOf(obj);//((PACKET_DATA)obj).TotalBytes; // 구조체에 할당된 메모리의 크기를 구한다.
IntPtr buff = Marshal.AllocHGlobal(datasize); // 비관리 메모리 영역에 구조체 크기만큼의 메모리를 할당한다.
Marshal.StructureToPtr(obj, buff, false); // 할당된 구조체 객체의 주소를 구한다.
byte[] data = new byte[datasize]; // 구조체가 복사될 배열
Marshal.Copy(buff, data, 0, datasize); // 구조체 객체를 배열에 복사
Marshal.FreeHGlobal(buff); // 비관리 메모리 영역에 할당했던 메모리를 해제함
return data; // 배열을 리턴
}
좀 소스 그대로긴 해도 소켓통신에서 사용할때 도움이 많이 될거 같습니다.
그리고 사용시 주의 사항은 Marshal.SizeOf(obj); 이부분입니다.
struct PACKET_DATA
{
public int PacketType; // 패킷 타입
public int TotalBytes;
public byte[] Data;// 배열길이 1024
}
이런 구조체가 있다면 ..
Marshal.SizeOf(obj)는 byte의 배열 을 생각 안하고
사이즈를 무조건 12를 리턴합니다.
그럼 네트워크 통신에 데이터를 다 못 보내기 때문에~~
구조체 안에 크기를 선언해줍니다.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct PACKET_DATA
{
public int PacketType; // 패킷 타입
public int TotalBytes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
public byte[] Data;//byte배열 길이 1024
}
그럼 Marshal.SizeOf(obj)는 1032를 리턴합니다~~~
출처: https://technodori.tistory.com/entry/C-byte-구조체-구조체-byte [Moons]
=================================
=================================
=================================
출처: http://cafe.daum.net/_c21_/bbs_search_read?grpid=1GE41&fldid=JZhy&datanum=5
요즘 Win32API 소켓통신을 C#에 심고 있는데 C#은 강제 형변환이 어렵더라고요..ㅠㅠ C#을 오랜만에 해봐서~ㅎㅎ 그래서 한~참을 뒤적 거리다 좋은걸 찾아서 올립니다~ //byte 배열을 구조체로 public static object ByteToStructure(byte[] data, Type type) { IntPtr buff = Marshal.AllocHGlobal(data.Length); // 배열의 크기만큼 비관리 메모리 영역에 메모리를 할당한다. Marshal.Copy(data, 0, buff, data.Length); // 배열에 저장된 데이터를 위에서 할당한 메모리 영역에 복사한다. object obj = Marshal.PtrToStructure(buff, type); // 복사된 데이터를 구조체 객체로 변환한다. Marshal.FreeHGlobal(buff); // 비관리 메모리 영역에 할당했던 메모리를 해제함 if (Marshal.SizeOf(obj) != data.Length)// (((PACKET_DATA)obj).TotalBytes != data.Length) // 구조체와 원래의 데이터의 크기 비교 { return null; // 크기가 다르면 null 리턴 } return obj; // 구조체 리턴 } // 구조체를 byte 배열로 public static byte[] StructureToByte(object obj) { int datasize = Marshal.SizeOf(obj);//((PACKET_DATA)obj).TotalBytes; // 구조체에 할당된 메모리의 크기를 구한다. IntPtr buff = Marshal.AllocHGlobal(datasize); // 비관리 메모리 영역에 구조체 크기만큼의 메모리를 할당한다. Marshal.StructureToPtr(obj, buff, false); // 할당된 구조체 객체의 주소를 구한다. byte[] data = new byte[datasize]; // 구조체가 복사될 배열 Marshal.Copy(buff, data, 0, datasize); // 구조체 객체를 배열에 복사 Marshal.FreeHGlobal(buff); // 비관리 메모리 영역에 할당했던 메모리를 해제함 return data; // 배열을 리턴 } 좀 소스 그대로긴 해도 소켓통신에서 사용할때 도움이 많이 될거 같습니다. 그리고 사용시 주의 사항은 Marshal.SizeOf(obj); 이부분입니다. struct PACKET_DATA { public int PacketType; // 패킷 타입 public int TotalBytes; public byte[] Data;// 배열길이 1024 } 이런 구조체가 있다면 .. Marshal.SizeOf(obj)는 byte의 배열 을 생각 안하고 사이즈를 무조건 12를 리턴합니다. 그럼 네트워크 통신에 데이터를 다 못 보내기 때문에~~ 구조체 안에 크기를 선언해줍니다. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] struct PACKET_DATA { public int PacketType; // 패킷 타입 public int TotalBytes; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] public byte[] Data;//byte배열 길이 1024 } 그럼 Marshal.SizeOf(obj)는 1032를 리턴합니다~~~ 다른 주의 사항도 있는데 함 필요할때 해보세요~ |
=================================
=================================
=================================
출처: https://shine10e.tistory.com/117
Struct 를 Byte 로, Byte 를 Struct 로 변환하는 소스 입니다.
public static byte[] StructToByte(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(obj, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr;
}
public static T ByteToStruct<T>(byte[] buffer) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
if (size > buffer.Length)
{
throw new Exception();
}
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(buffer, 0, ptr, size);
T obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
Marshal.FreeHGlobal(ptr);
return obj;
}
출처: https://shine10e.tistory.com/117 [열이 Blog : )]
=================================
=================================
=================================
'프로그래밍 관련 > 언어들의 코딩들 C++ JAVA C# 등..' 카테고리의 다른 글
[C#] 문자열 <-> 바이트(byte) 상호변환 그리고 문자열 인코딩(EncodingInfo.GetEncoding Method) 관련 (0) | 2019.03.14 |
---|---|
[C#] 소켓 통신 시 구조체,바이너리, 마샬링 등등 사용하기 관련 (0) | 2019.03.13 |
[C#] Buffer.BlockCopy 으로 byte[] 데이터를 memmove, memcpy()처럼 이용 관련 (0) | 2019.03.13 |
[C#] Sizeof, Marshal.SizeOf Method 형 크기 SizeOf 관련 (0) | 2019.03.13 |
[C#] C++ 와 C# 형 비교 참조 Converting C++ Data Types to C# (0) | 2019.03.13 |
댓글 영역