2009-07-21 6 views
4

TCP/IP 연결을 통해 보낼 필요가있는 일련의 메시지가있는 상황이 계속 발생합니다. 나는 결코 메시지 클래스의 디자인을위한 좋은 해결책을 찾지 못했다. 모든 메시지가 파생 된 메시지 기본 클래스를 갖고 싶습니다. 각 메시지마다 다른 필드가 있으므로 멤버 변수 나 메서드를 통해 필드에 액세스 할 수 있습니다. 뭔가 같은 ...TCP/IP 연결을 통한 스트리밍

class message_base 
{ 
    public: 
    message_base(); 
    virtual ~message_base(); 

    unsigned int type; 
}; 

class message_control : public message_base 
{ 
    public: 
    message_control(); 
    virtual ~message_control(); 

    unsigned int action; 
}; 

나는 message_control를 만들고에 할당하고에서 읽기위한 액션 멤버에 액세스 할 수 있습니다이 방법. 너무 많은 코드를 작성하지 않고도 메시지를 전달할 수 있습니다.

메시지를 보낼 때 문제가 발생합니다. < < 연산자를 재정의하고 >> 연산자를 사용하면 한 번에 하나의 변수를 통해 메시지를 보낼 수 있습니다. 이 솔루션의 문제점은 데이터를 보내려는 호출이 많을수록 컨텍스트 스위치가 프로세서를 슬램하게 만드는 것입니다. 또한, 스트리밍 연산자는 소켓 클래스를 끝내고 그것이 선호하는 메시지 클래스가 아닙니다. 내가 버퍼의 데이터를 팩 경우

socket& socket::operator<<(message_control& message) 
{ 
    sock << type; 
    sock << action; 
} 

, 나는 멀리 C에서 ++보다 C의 영역으로 얻을 포인터 등의 관대 한 사용을 만드는 자신을 찾을 수 있습니다. 코드 수정이 어렵고 오류가 발생하기 쉽습니다. 그리고 스트리밍 연산자는 아직 소켓 클래스에 있고 메시지 클래스에는 없습니다.

socket& socket::operator<<(message_control& message) 
{ 
    byte* buffer = new byte[sizeof(message.type) + sizeof(message.action)]; 

    memcpy(buffer, message.type, sizeof(message.type)); 
    memcpy(buffer + sizeof(message.type), message.action, sizeof(message.action)); 

    sock.send(buffer); 
} 

마지막으로 중간 클래스를 사용하여 버퍼의 멤버를 압축하고 압축을 풀었습니다. 메시지는 연산자 < <을 구현하고 연산자 >>를 버퍼 클래스에 구현 한 다음 버퍼 클래스를 소켓으로 보낼 수 있습니다. 이 작동하지만 옳은 생각하지 않습니다.

class socket 
{ 
    public: 
    socket(); 
    ~socket(); 

    socket& operator<<(buffer& buff); 
}; 

class buffer 
{ 
    public: 
    buffer() {m_buffer = new byte[initial_size];} 
    ~buffer() {delete [] m_buffer;} 

    buffer& operator<<(unsigned int value); 

    private: 
    byte* m_buffer; 
}; 

void message_control::serialize(buffer& buff) 
{ 
    buff << type; 
    buff << action; 
} 

나는이 문제에 대한 우아한 해결책을 느낄 수밖에 없다. 내가 성취하려고하는 것과 일치하는 디자인 패턴을 찾을 수 없습니다. 누구든지이 문제를 경험하고 좋은 오래된 포인터와 바이트 배열을 사용하는 것이 더 나을 것 같은 기분이 들지 않는 디자인을 제안 했습니까?

업데이트

은 내가 가장 자주 아주 잘 와이어 프로토콜을 정의 취급하고 내 원래의 게시물에서 언급하지 못했습니다. 그래서 일반적으로 내 솔루션을 롤업해야하며 네트워크 연결을 통해 메시징에 사용할 수있는 훌륭한 툴킷을 사용할 수 없습니다.

+0

당신은 ACE를 사용하여 봤어 바꾸기? – Alan

+0

아마도 그다지 도움이되지 않을 것입니다. 그러나 나는 당신의 마지막 패턴과 거의 동일한 패턴을 구현했습니다. 내 경우를 제외하고는 버퍼가 좀 더 정당했기 때문에 각 메시지와 함께 전달할 다소 큰 구조가 있었기 때문에 버퍼가 매우 유용하고 내 마음에 적절 해졌습니다. 그럼에도 불구하고 그것은 잘 작동하고 큰 데이터를 전달하지 않더라도 똑같이 잘 작동합니다! – DeusAduro

+0

DeusAduro - 나는 또한 이것을 (100의 KB에) 메시지와 함께 사용할 필요가있었습니다. 무겁게 스레드 환경에서 잘 작동하는 버퍼 클래스가 생기면 훨씬 쉽게 작업 할 수 있습니다. 나는 그것이 최선의 해결책이라는 것을 알았고 나는 유일하게 기쁘다. –

답변

1

"데이터를 보내려는 호출이 많을수록 컨텍스트 스위치가 프로세서를 슬래 밍하고 스트리밍 연산자가 소켓 클래스를 끝내고 선호하는 메시지 클래스가 아닙니다. 살았다. "

두 번째 문제에 대한 해결책은 소켓 클래스의 멤버 함수 대신 메시지 클래스가 들어있는 네임 스페이스에서 operator<<을 비 멤버 함수로 정의하는 것입니다. ADL이 그것을 찾을 것입니다.

첫 번째 문제에 대한 해결책은 프로세스 내에서 데이터를 버퍼링 한 다음 각 메시지의 끝에서 플러시하는 것입니다. Nagle 버퍼링이 컨텍스트 스위치를 막지 못한다면, 소켓을 망쳐 놓음으로써 이것을 달성 할 수 있을지도 모르겠다. 하지만 확실히 할 수있는 일은 C++ 방식으로 보내기 전에 각 메시지를 준비하는 것입니다.와

sock << type; 
sock << action; 

:

stringstream ss; 
ss << type; 
ss << action; 
sock << ss.str(); 
관련 문제