Develope/C#2013. 3. 26. 11:47

요즘 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
Posted by AsCarion