2010-06-16 3 views
3

TCP/IP를 통해 전송해야하는 열거 형 멤버가 포함 된 여러 가지 구조체가 많이 있습니다. 통신 종단점이 다른 운영 체제 (Windows XP 및 Linux)에서 다른 컴파일러 (gcc 4.x.x 및 MSVC 2008)를 의미하지만 두 프로그램 모두 동일한 헤더 파일을 형식 선언과 공유합니다.C에서 소켓을 통해 열거 형 값을 포함하는 구조체를 보내는 가장 좋은 방법은 무엇입니까

성능상의 이유로 구조를 내부적으로 비싼 직렬화 또는 스트리밍없이 직접 전송해야합니다 (아래 코드 샘플 참조).

그래서 두 컴파일러가 열거 형 멤버에 대해 동일한 내부 메모리 표현을 사용하는지 확인하는 것이 좋습니다 (즉 둘 다 32 비트 부호없는 정수를 사용). 두 엔드 포인트가 리틀 엔디안 maschines합니다이기 때문에 또는 엔디안 여기에 문제가되지 않습니다 ... 또한

//type and enum declaration 
typedef enum 
{ 
    A  = 1, 
    B  = 2, 
    C  = 3 
} eParameter; 


typedef enum 
{ 
    READY = 400, 
    RUNNING = 401, 
    BLOCKED = 402 
    FINISHED = 403 
} eState; 


#pragma pack(push,1) 
    typedef struct 
    { 
     eParameter mParameter; 
     eState mState; 
     int32_t miSomeValue; 
     uint8_t miAnotherValue; 
     ... 
    } tStateMessage; 
#pragma pack(pop) 


//... send via socket 
tStateMessage msg; 
send(iSocketFD,(void*)(&msg),sizeof(tStateMessage)); 

//... receive message on the other side 
tStateMessage msg_received; 
recv(iSocketFD,(void*)(&msg_received),sizeof(tStateMessage)); 

...

  • 이 문제를 해결하기 위해 더 나은 방법이 있는지.
  • 팩 #pragma는 정렬 문제를 만족스럽게 해결합니다. 귀하의 답변

들으, 악셀

답변

1

난 당신이 (가능한 단점에 대한 성능 향상을 무게 후 상대적으로 위험한 경로를 선택했습니다 실용적으로하기 때문에 귀하의 질문에 대답거야 적어도 나는 당신이 희망!).

이러한 컴파일러의 향후 변경에 대한 이식성과 견고성 또한 고려한 경우 경험적 접근 방식이 문제에 대한 최상의 보호가됩니다.

  1. 모든 경우에 열거 형에 대해 초기화 프로그램을 사용하고 있는지 확인하십시오 (예 :이 예 참조).
  2. 받는 측에서 데이터가 어떻게 해석되는지를 경험적으로 테스트하십시오.
  3. 빌드 도구의 버전 번호를 양면에 기록하고 소스 코드로 보관하십시오. 툴을 보관하는 것이 바람직합니다.
  4. 예기치 않은 유지 관리가 장애가있는 것은 아니므로 모든 것을 문서화하십시오.
  5. 최상의기도를 위해기도하십시오! ;-)
+0

어, 팁 3, 4 들으! 맞습니다. 빌드 도구의 버전 번호가 유지 관리에 도움이 될 수 있습니다! (나는 이미 1,2,5를 돌보고있다.) – Axel

+0

또한 데이터의 크기를 표준화하고 전송을 위해 그 크기의 정수로 /에서 캐스팅해야한다. – nategoose

1

내가 좋아하는, 특별히 이러한 문제를 위해 설계 직렬화 라이브러리 중 하나를 사용하기를 권합니다 :

당신이 얻을 수있는 것은 ma입니다. ximum 플랫폼 이식성, 인터페이스 및 메시지 유형을 변경하는 쉬운 방법 플러스 훨씬 더 유용한 기능.

Avro 만 공식적으로 지원되는 C API를 가지고 있습니다. Thrift 및 프로토콜 버퍼의 경우 C++ API에 대해 thin C 래퍼를 만들거나 protobuf-c과 같은 C API 중 하나를 사용합니다.

1

이것은 조숙 한 최적화입니다. 측정하지 않고 두 가지 값 비싼 가정을했습니다.

첫 번째 가정은 코드의이 부분이 처음에는 성능 병목 현상이라는 것입니다. 그렇지? 아주있을 법하지 않습니다. 성능에 대한 가정을 할 경우 네트워크 메시지를 보내고받는 코드가 아니라 네트워크 속도가 병목 현상이라는 가정이 안전한 것으로 가정합니다. 이것만으로도 두 번째 가정을 고려하는 것을 막을 수 있습니다.

두 번째 가정은 구조체의 원시 비트를 쓰는 것보다 구조체를 이식 가능하게 직렬화하는 것이 눈에 띄게 느립니다. 이 가정은 거의 항상 거짓입니다.

회의적인? 그것을 측정하십시오! :)

+0

* 예, 속도가 중요한 문제입니다. 내 질문에 실시간 환경에 대해 언급하는 것을 잊어 버렸습니다 ... *하지만 당신은 아마 직렬화 오버 헤드를 측정해야합니다. – Axel

0

어떤 방식 으로든 데이터를 직렬화하거나 적어도 하드웨어 아키텍처에 대한 표시기를 사용하는 것이 좋습니다. 동일한 컴파일러를 사용하더라도 내부 데이터 표현 (리틀 엔디안, 빅 엔디안 등)에 문제가있을 수 있습니다.

1

직렬화를 사용하지 않으려는 경우, 사용 된 한 가지 방법은 enum을 피하고 단순히 32 비트 부호없는 int 및 #DEFINE을 사용하여 enum을 에뮬레이션하는 것입니다. 데이터 형식에 대한 일부 보증을 위해 형식 안전성을 교환합니다.

그렇지 않으면 모든 컴파일러에서 동일한 방식으로 구현되도록 언어 사양에서 보장하지 않는 동작에 의존합니다. 일반 이식성에 대해 걱정하지 않고 두 컴파일러에서 동일한 효과를 보장하려는 경우 시행 착오와 많은 테스트를 통해 두 사람이 동일한 작업을 수행 할 수 있어야합니다. 나는 C99 스팩이 enum이 내부적으로 int보다 크거나 작지만 int보다 크지 않다는 것을 믿는다. 그래서 나는이 가정으로 올바른 방향으로 컴파일러를 암시하기 위해 수행 본 적이 한 가지입니다

typedef enum 
{ 
    READY = 400, 
    RUNNING = 401, 
    BLOCKED = 402, 
    FINISHED = 403, 
    MAX  = MAX_INT 
} eState; 

이 열거를 저장하는 방법에 대한 컴파일러의 선택을 제한해야합니다. 컴파일러는 표준에 위배 될 수 있지만 gcc는 필요하다면 64 비트 열거 형을 허용하는 비표준 기능을 가지고 있음을 알고 있습니다.

또한

, 체크 아웃 : What is the size of an enum in C?

+0

* 유형 안전 거래는 옵션이지만, 포기하지 않는 것이 좋습니다. * thx는 가짜 항목에 "MAX"아이디어가 있습니다! – Axel

관련 문제