2013-01-21 2 views
3

아래의 첫 번째 코드 조각 (GenericMessage.hxx에 정의 됨)에 표시된 GenericMessage라는 클래스가 있습니다.ZMQ : ZMQ 큐를 통해 사용자 지정 CPP 개체 보내기

ZMQ 대기열을 통해 GenericMessage 클래스의 인스턴스를 보내려고하는 TestFE.cpp 파일 (아래의 두 번째 코드 스 니펫 참조)이 있습니다 (아래의 네 번째 코드 스 니펫 - ZmqHandler.hxx 참고). TesfFE.cpp는 ZmqHandler.hxx를 포함하여 여기에 ZMQ 푸시 패턴을 구현합니다.

ZMQ 대기열을 통해 이렇게 언급 된 GenericMessage 인스턴스를받는 TestBE.cpp라는 파일 (아래의 세 번째 코드 스 니펫 참조)이 있습니다. TestBE.cpp는 ZMQ 큐를 통해 GenericMessage 인스턴스를 검색하기 위해 여기에 ZMQ 풀 패턴을 구현합니다.

TestFE.cpp에서 GenericMessage 객체를 ZMQ 대기열에서 수용 할 수있는 형식으로 변환하기 위해 표준 memcpy 함수를 사용합니다. TestBE.cpp (주석의 세 번째 코드 단편에 표시되어 있음)의 21 줄에서 memcpy가 TestFE.cpp 인 송신자 측에서 제대로 작동하지 않기 때문에 세그먼트 화 오류가 발생합니다. TestBE가 실행될 때 아래 메시지가 나타납니다. 나는 또한 바로 아래 gdb 백 트레이스를 제공하고있다. 여기서 뭐가 잘못 됐는지 말해 줄래? 왜 memcpy가 내 GenericMessage 객체를 ZMQ message_t 형식으로 제대로 복사 할 수 없다고 생각합니까? 아니면 다른 문제라고 생각합니까? 모든 의견을 주시면 감사하겠습니다.

오류 메시지

$ ./TestBE 
    Connecting to FE... 
    RECEIVED: 1 
    Segmentation fault (core dumped) 

GDB 역 추적

(gdb) r 
    Starting program: /home/holb/HOLB_DESIGN/ZMQ/WORK1/TestBE 
    [Thread debugging using libthread_db enabled] 
    Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1". 
    [New Thread 0xb7c84b40 (LWP 4252)] 
    [New Thread 0xb7483b40 (LWP 4253)] 
    Connecting to FE... 
    RECEIVED: 1 

    Program received signal SIGSEGV, Segmentation fault. 
    0xb7f371cc in std::basic_string<char, std::char_traits<char>, std::allocator<char>  >::basic_string(std::string const&)() 
    from /usr/lib/i386-linux-gnu/libstdc++.so.6 
    (gdb) bt 
    #0 0xb7f371cc in std::basic_string<char, std::char_traits<char>,  std::allocator<char> >::basic_string(std::string const&)() 
    from /usr/lib/i386-linux-gnu/libstdc++.so.6 
    #1 0x08049621 in GenericMessage<std::string>::getData (this=0xbffff06c) 
    at GenericMessage.hxx:18 
    #2 0x08049075 in main() at TestBE.cxx:21 
(gdb) 

1 코드 조각 (GenericMessage.hxx) #INCLUDE #INCLUDE #INCLUDE

,363,210
template <class T> 
    class GenericMessage { 
    public: 

     GenericMessage(int id, T msg): 
     beId(id), 
     data(msg) 
     {} 

     ~GenericMessage(){} 

     T getData() 
     { 
      //LINE 18 is the following line! 
      return data; 
     } 

      std::string toString() 
      { 
       std::ostringstream ss; 
       ss << getBeId(); 
       std::string ret = ss.str(); 

       return ret; 
      } 

      void setBeId(int id) 
      { 
       beId = id; 
      } 

      int getBeId() 
      { 
      return beId; 
      } 
private: 
     int beId; 
     T data; 
}; 

2 코드 조각 (TestFE.cxx ==> 발신자) 사용법 #include "ZmqHandler.hxx" 가 //

int main() 
{ 
    ZmqHandler<std::string> zmqHandler; 
    int counter = 1; 

    while(1) 
    { 
     std::string data = "Hello there!\0"; 
     GenericMessage<std::string> msg(counter, data); 
     zmqHandler.sendToBE(&msg); 
     counter++; 
     sleep(1); 
    } 

    return 0; 
} 
ZmqHandler.hxx

의 내용에 대해서는 아래에서 4 니펫보기

코드 조각 3 (TestBE.cxx ==> 수신기)

#include "zmq.hpp" 
    #include "GenericMessage.hxx" 
    #include <string> 
    #include <iostream> 

    int main() 
    { 
     // Prepare our context and socket 
     zmq::context_t context (1); 
     zmq::socket_t socket (context, ZMQ_PULL); 

    std::cout << "Connecting to FE..." << std::endl; 
    socket.connect ("tcp://localhost:5555"); 

    while(1){ 
     zmq::message_t reply; 
      socket.recv (&reply); 
      GenericMessage<std::string> *msg = (GenericMessage<std::string>*)(reply.data());     
      std::cout << "RECEIVED: " << msg->toString() << std::endl; 

      /* ********************************* */ 
      /* SEGMENTATION FAULT HAPPENS HERE */ 
      /* The member "data" in class GenericMessage cannot be received while the member "id" in the previous line can be received. */ 
      std::cout << "DATA: " << ((std::string)msg->getData()) << std::endl; 
      /* ********************************** */ 
    } 

    return 0; 
} 

코드 조각 4 (ZMQHandler.hxx)

#include "zmq.hpp" 
    #include "GenericMessage.hxx" 
    #include <pthread.h> 
    #include <unistd.h> 
    #include <cassert> 

    template <class T> 
    class ZmqHandler { 
    public: 
     ZmqHandler(): 
    mContext(1), 
    mOutbHandlerSocket(mContext, ZMQ_PUSH) 
     {  
      mOutbHandlerSocket.bind ("tcp://*:5555");  
     } 

     ~ZmqHandler() {} 

     void *sendToBE(GenericMessage<T> *theMsg) 
     { 
     // Place the new request to the zmq queue for BE consumption 
     zmq::message_t msgToSend(sizeof(*theMsg)); 

     memcpy (msgToSend.data(), ((GenericMessage<T>*)theMsg), sizeof(* ((GenericMessage<T>*)theMsg))); 

     mOutbHandlerSocket.send(msgToSend); 

     std::cout << "SENT request: [" << theMsg->toString() << "]" << std::endl; 

     return (NULL); 
     } 

    private: 
     zmq::context_t mContext; 
     zmq::socket_t mOutbHandlerSocket; 

}; 
+0

제목이 ZMQ 실패로 유감스럽게 생각합니다 ... 아마도 내 코드가 ZMQ에 실패했습니다.따라서 누군가가 기분을 상하게하는 경우 제목은 속임수가 아니며 미안합니다. –

+0

GenericMessage.hxx 파일에서 18 번째 줄을 지적하면 도움이 될 것입니다. 게다가 GDB의'up' 명령을 사용하여 호출 스택을 올라갈 수 있습니다. 따라서 코드에 도달하면 변수를 검사하여 값을 확인할 수 있습니다. –

+0

감사합니다. GenericMessage.hxx를 포함하여 첫 번째 코드 스 니펫에서 18 번째 줄을 가리키고 있습니다. –

답변

3

나는이 문제를보기 시작했다. 포인터 (std::string)가있는 멤버 변수가 포함 된 완전한 "구조체"를 보내는 것입니다. 포인터는 포인터를 만든 프로그램에서만 유효하기 때문에이 작업을 수행 할 수 없습니다.

구조체를 보내기 전에 serialize 구조체에 넣은 다음 수신 측에서 역 직렬화해야합니다.

Boost serialization 또는 Google protocol buffers 또는 기타 라이브러리 수와 같은 라이브러리를 사용할 수 있습니다.