C/C++ 및 C# Scoket 통신

 
 
Introduction

  본 블로그의 포스팅과 관련된 내용을 작성한지 몇년이 지났는데, 에버노트를 정리하다가 버릴까 하던 내용을 다시 다시 주워서 정리 후 포스팅합니다.  최근에는 C/C++을 이용한 개발이 native형태되면서 UI는 기타 다른 언어들을 많이 사용하고 있습니다. 그래서 기존에 만들어 둔 C/C++ based network socket 모듈을 버릴 수 없어 한동안 열심히 찾아봤습니다. 
  또한, 최근 비대면 서비스가 활발해짐에 따라 다양한 플랫폼을 연결시켜야 하는 문제가 있습니다. Web, PC(Windows), MacOS, Android, iOS는 기본으로 하고 그외 다른 플랫폼들도 연결이 되어야 하죠. 다양한 플랫폼을 위한 통합 개발툴도 많이 있긴하지만, native를 써야하는 상황이 올 때는 언젠가는 꼭 알아두고 넘어가야하는 문제가 아닐까 합니다. 물론 자본이 있다면, 그 툴을 구매해서 쓰시는게… 좋죠. 
 
조금 서론이 길었지만, C/C++ 및 C#의 네트워크 소켓 통신을 먼저 포스팅 합니다. 그리고 이후에 현재 개발진행중인 프로젝트에서 모바일과의 연동 모듈을 개발하고 있는데 추후 시간이 될 때 또 포스팅을 하도록 하겠습니다. 
 

 

 

 

 
# 패킹(packing)과 마샬링(Marshaling)

  네트워크 소켓 프로그래밍을 할 경우, 주고 받는 데이터의 크기를 동일시 해야하기 때문에 패킹(packing)을 해야합니다. C/C++에서의 패킹과 C#에서의 패킹을 하는 방법이 다르기 때문에 아래와 같이 참조 하여 사용하시면 됩니다. 사용 방법은 간단하나, 네트워크에 익숙하지 않은 분들이 항상 놓치는 부분들이니 꼭 명심하고 추가 하시기 바랍니다.   
 
  • 주의사항
    • 통신을 진행하면서, C/C++ <---> C# 에서 자료형의 크기를 맞춰줘야함 
    • C#에서는 C,C++ 과 자료형이 다르기때문에 자료형을 참조하여 맞춰주기만 하면 제대로 전달 됨
  • C/C++ side 
    • DWORD // 4 byte
    • WORD // 2byte
    • typedef unsigned long DWORD   // C# 에서는 int와 동일 (4 byte)
    • typedef unsigned short WORD   // C# 에서는 short와 동일 (2 byte)
 
 
C/C++ side
  • C/C++ 에서는 packet.h 파일 아래 아래와 같이 사용하시면 됩니다. 혹은 패킷을 보내는 구조체 사이에 추가 하시면 됩니다. 
// packet.h 파일

#pragma pack(push)
#pragma pack(1)

typedef struct socket_data
{
       DWORD msg;
       WORD size;
       WORD type;
       char data[128];
}SOCKET_DATA, *LP_SOCKET_DATA;

#pragma pack(pop)
 
# C# side
  • C#은 사용하는 패킷 구조체의 상단에 아래의 코드를 추가 하시면 됩니다. 
namespace ICPClientCSharp.Packet
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)] // <---패킹 작업
    class PKT_USERTALK : PacketHeader
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10 )] public char[] name;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public char[] UserBuf;
    }
}​


C/C++ 및 C# 통신 코드예제

  이제 C/C++ 및 C#의 코드를 통신하는 코드를 확인 해보도록 하겠습니다. 먼저 C/C++기반의 코드를 먼저 살펴보도록 하겠습니다. 
 
C/C++ based
#pragma pack(push)
#pragma pack(1)
typedef struct socket_data
{
       DWORD msg;
       WORD size;
       WORD type;
       char data[128];
}SOCKET_DATA, *LP_SOCKET_DATA;

#pragma pack(pop)​
C# baed
[StructLayout(LayoutKind.Sequential)]
public class socket_data
{
    public int msg;
    public short size;
    public short type;           
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] public char[] data;
}

패킹과 마샬링을 이용하여 먼저 상위 코드와 같이 구조체를 정의하면 끝이 납니다. 
간단하죠? 이제 소스코드를 주고 받는 부분을 확인해보도록 하겠습니다. 
 

 

 

 
# (Server side) C,C++에서 데이터를 받는 방법
LP_SOCKET_DATA data = (SOCKET_DATA*)malloc(sizeof(SOCKET_DATA));
ZeroMemory(data, sizeof(SOCKET_DATA));

strLen=recv(hSockArray[index-WSA_WAIT_EVENT_0],(char*)data, sizeof(SOCKET_DATA), 0);
send(hSockArray[index-WSA_WAIT_EVENT_0], (char*)data, sizeof(SOCKET_DATA),0);

cout << "msg : " << data->msg << "\r\n";
cout << "size: " << data->size << "\r\n";
cout << "type: " << data->type << "\r\n";
cout << "data: " << data->data << "\r\n";
cout << endl << "size(org): " << sizeof(SOCKET_DATA) << endl;

#(Client side) C# 에서 데이터를 전송하는 방법
socket_data s_data = new socket_data();
s_data.data = new char[100];
string strData = "testString";
s_data.msg = 1;
s_data.size = (short)(Marshal.SizeOf(typeof(socket_data)));
s_data.type = 5;
               
int len = strData.Length;
for (int idx = 0; idx < len; idx++)
    s_data.data[idx] = strData[idx];
byte[] packet = new byte[1];
StructToBytes(s_data, ref packet);
socket.Send(packet);​

// function 참조 

        public static void StructToBytes(object obj, ref byte[] packet)
        {
            int size = Marshal.SizeOf(obj);
            packet = new byte[size];
            IntPtr buffer = Marshal.AllocHGlobal(size+1);
            Marshal.StructureToPtr(obj, buffer, false);
            Marshal.Copy(buffer, packet, 0, size);
            Marshal.FreeHGlobal(buffer);
        }
        public static void BytesToStructure(byte[] bValue, ref object obj, Type t)
        {
            int size = Marshal.SizeOf(t);
            IntPtr buffer = Marshal.AllocHGlobal(size);
            Marshal.Copy(bValue, 0, buffer, size);
            obj = Marshal.PtrToStructure(buffer, t);
            Marshal.FreeHGlobal(buffer);
        }
코드만 보면(?) 알 수 있을 것 같아 별다른 설명은 달지 않았습니다. 
 

 

 

 

이 글을 공유하기

댓글(0)

Designed by JB FACTORY