상세 컨텐츠

본문 제목

[C#] C#의 클래스 혹은 구조체(class, struct)를 byte[]로 변환하는 방법 또는 반대로

본문

반응형

 

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

출처: 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;
}
 

 

 

반응형

 

728x90

 

 

 

=================================

=================================

=================================

 

 

 

출처: https://technodori.tistory.com/entry/C-byte-%EA%B5%AC%EC%A1%B0%EC%B2%B4-%EA%B5%AC%EC%A1%B0%EC%B2%B4-byte

 

 //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 : )]

 

 

 

=================================

=================================

=================================

 

 

반응형


관련글 더보기

댓글 영역