요즘 C#을 이용해서 기존에 MFC로 구현하던 클라이언트를 다시 만들고 있다.
공부도 할겸 겸사겸사 해서.. (처음이라 좀 힘들긴 하네..)
Socket 으로 서버에 데이터를 보내려니,
한방에 몰아 보내려니까 이게 잘 안되더라...
기본 개념은,
1. 헤더 structure 생성 및 데이터 삽입
2. 바디 Structure 생성 및 데이터 삽입
3. 헤더 byte로 변환 후 서버로 전송
4. 바디 byte로 변환 후 서버로 전송
5. 서버로부터 응답 패킷 수신
인데.. 여기서 막히는게 몇가지 있었다.
1. string 형태의 데이터를 고정크기의 byte[]에 대입 시 크기가 변해버리는 문제
- 이로 인해 송신 할 패킷의 크기가 변해버려서 제대로 송신 할 수가 없었다.
- 또한, 이 데이터가 포함된 Structure를 byte[]로 변환 시 Access Violation 발생...
- 데이터 추가 된 이후의 크기가 작아져버리니.. 휴..
2. 여러개의 데이터를 하나의 byte[]로 넣으려면 어떻게 해야할까 고민..
3. 수신된 헤더+바디 이상의 데이터를 어떻게 파싱해야 할까??
그래서 필요한 메서드를 만들었다.
일단, 처음 Structure 를 Define 할때 아래와 같은 형식이 필요하다.
[Serializable] [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct _USER_INFO_BODY_ { public uint uClientID; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32] public byte[] cID; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16] public byte[] cPW; public uint uLogin; public _USER_INFO_BODY_(bool bInital) { uClientID = 0; cID = new byte[32]; cPW = new byte[16]; uLogin = 0; } }
여기서 SizeCont 로 byte[]의 크기를 지정해주고 시작한다.
1. String 값을 ASCII Byte Array로 변환
// String 값을 ASCII byte Array 로 변환하는 함수 public static byte[] StringToByte(string obj, int dstSize) { int nSize = obj.Length; byte[] arr = new byte[dstSize]; IntPtr ptr = Marshal.AllocHGlobal(nSize); Buffer.BlockCopy(Encoding.ASCII.GetBytes(obj), 0, arr, 0, nSize); Marshal.FreeHGlobal(ptr); return arr; }dstSize 값은 원래의 고정 크기를 넣어준다.
고정 크기 값을 가진 Buffer를 생성하여, 거기에 string의 길이만큼만 복사하는 방식이다.
2. Structure 정보를 Byte Array로 변환하는 함수
// Structure 정보를 Byte Array로 변환하는 함수 public static byte[] StructToByte(object obj) { int nSize = Marshal.SizeOf(obj); byte[] arr = new byte[nSize]; IntPtr ptr = Marshal.AllocHGlobal(nSize); Marshal.StructureToPtr(obj, ptr, true); Marshal.Copy(ptr, arr, 0, nSize); Marshal.FreeHGlobal(ptr); return arr; }파라메터의 Obj 의 크기만큼 arr 생성 후, 그 길이만큼 복사한다.
C의 memcpy 와 비슷하다.
(그래서 나 같은 경우는 친근하다.)
3. Structure 일부 정보를 버퍼의 Offset 부터 저장하는 함수
// Structure 일부 정보를 Offset 부터 버퍼에 저장하는 함수 public static void StructToByte(ref byte[] buf, object obj, int nOffset) { int nSize = Marshal.SizeOf(obj); IntPtr ptr = Marshal.AllocHGlobal(nSize); Marshal.StructureToPtr(obj, ptr, true); Marshal.Copy(ptr, buf, nOffset, nSize); Marshal.FreeHGlobal(ptr); }
4. Byte Array를 Structure로 변환하는 함수
// Byte Array를 Structure 로 변환하는 함수 public static T ByteToStruct<t>(byte[] buffer) where T : struct { int nSize = Marshal.SizeOf(typeof(T)); if (nSize > buffer.Length) { throw new Exception(); } IntPtr ptr = Marshal.AllocHGlobal(nSize); Marshal.Copy(buffer, 0, ptr, nSize); T obj = (T)Marshal.PtrToStructure(ptr, typeof(T)); Marshal.FreeHGlobal(ptr); return obj; }byte[]의 값을 원하는 Structure의 크기로 할당하여 값을 복사한다.
Structure의 크기가 buffer보다 작은 경우는 예외처리 한다.
5. Byte의 Offset 부터 Structure로 변환하는 함수
// Byte의 Offset 부터 Structure로 변환하는 함수 public static T ByteToStruct<t>(byte[] buffer, int nOffset) where T : struct { int nSize = Marshal.SizeOf(typeof(T)); if(nSize > buffer.Length - nOffset) { throw new Exception(); } IntPtr ptr = Marshal.AllocHGlobal(nSize); Marshal.Copy(buffer, nOffset, ptr, nSize); T obj = (T)Marshal.PtrToStructure(ptr, typeof(T)); Marshal.FreeHGlobal(ptr); return obj; }byte[] 데이터를 Structure에 맞게 잘라서 사용하기 위해 만든 메서드.
이건 아직 만들기만 하고 쓰진 않고 있다.
작업이 진행되면서 사용하게 되면 보강/수정 해야겠다.
'Develope > C#' 카테고리의 다른 글
Timer 사용하기 (0) | 2013.04.04 |
---|