我要做一个通过Socket通讯的程序,我的设计思路是,用一个线程来接收socket收到的数据,并把各个数据包放在一个缓冲区中,因为各种数据包使用了不同的结构来表示,因此缓冲区无法用一个统一的结构来保存数据,我就定义了一个具有指针成员的结构SCK_PACKET,用来保存各种不同的数据包.结构如下://包头的结构
typedef struct
{
u_long   totalLen ;   // 4bytes
u_long   cmdID ;         // 4bytes
u_long   seqID ;         // 4bytes
char version[8] ;        // 8bytes
} MsgHead ;//用于保存数据包到缓冲区的结构
typedef struct  
{
MsgHead struHead;           //包头
LPVOID lpPacketBody_Whole; //指向包体(整个包)的指void指针.
}SCK_PACKET;当监视socket的线程接到数据后,就把包头解释出来,放在struHead,lpPacketBody_Whole指向包体. MsgBindResp * pBindResp = new MsgBindResp;  //MsgBindResp是其中一个包通信数据包结构 SCK_PACKET sckPack;
sckPack.struHead = pBindResp->resp.head;     
sckPack.lpPacketBody_Whole = pBindResp;      //把当前的包体指针指向数据包体

//申请进入临界区
EnterCriticalSection(&m_Critical_Section);
m_CommnuicatCach.InsertPacket(sckPack);   //把这个SCK_PACKE存入map中,
//释放临界区
LeaveCriticalSection(&m_Critical_Section);////////////////////////////////////////
通过上面的办法,表面上的业务逻辑问题是解决了,但是我有个疑问:在上述代码中,解包的时候,为了得到一个包的指针,所以:MsgBindResp * pBindResp = new MsgBindResp;(开僻了一块内存),但当其它线程从map中读取了这个包,并在map中把这个包删除后,这个指针怎么办?会自己释放吗?还是要手动释放?从另外一线程里读的,怎么去把pBindResp的内存释放呢?

解决方案 »

  1.   

    一个可以肯定的是从map中删除SCK_PACKET时,是不会自动释放SCK_PACKET内的LPVOID所指响的内存区域,LPVOID是要手动释放
      

  2.   

    另外,由于LPVOID是void* ,你无法通过delete来释放一个void*的。
    你应该在SCK_PACKET内记录LPVOID所指响的内存的大小,然后用free来释放。
    当然,分配是用malloc,释放时用free。
    只是我的愚见,指教一下。
      

  3.   

    喔,那么说,就不能用new来申请这块内存了?只能用malloc?
      

  4.   

    那么我不想用指针来保存这些包,在map里有什么办法可以保存不同类型的数据作为元素呢?
      

  5.   

    喔,那么说,就不能用new来申请这块内存了?只能用malloc?
    先回答这个
    delete和new是搭配使用的,就正如你new的时候要指定类型,delete的时候同样要指定类型,而你的SCK_PACKET内的指针是无类型(void*),所以你delete一个void*的时候编译器无法确定void*所指向的内存有多少个字节,也就是无法正确释放内存了。
    这时你可能会回答,我强制类型转换不就ok啦。对,把void*转换成MsgBindResp *是可以,但是,你的SCK_PACKET内的void*不单单只是指向MsgBindResp吧,不然你为什么要用void*呢。
    你在释放SCK_PACKET内的void*时无法确定void*真正指向的是什么(也就是说你不知道要把void*转换成什么),自然也就无法用delete来释放了。
    用malloc/free配合sizeof就可以。
      

  6.   

    第二个问题,用boost;;any
    但同样需要类型转换,用boost的any_cast<>()
    最主要是你必须记得map内的每个对象的真正类型是什么,不然的话你无法进行类型转换
    ps:
    jvm和clr是如何的强大,来个反射不就搞定了。
      

  7.   

    修正一下:
    你应该在SCK_PACKET内记录LPVOID所指响的内存的大小
    其实这个不需要记录,因为free不需要指定大小,而malloc是需要的。
    给个例子:
    void* p = malloc(sizeof(MsgBindResp));
    //这里可以强制类型转换
    MsgBindResp * pBindResp = (MsgBindResp *)p;
    //这里做你应该做的事
      

  8.   

    删除的时候呢?我这样释放可以吗?
    //删除一个数据包//参数:lPacketKey:数据包的键
    long CCommunicationCach::DeletePacket(long lPacketKey)
    {
    //先把里面的LPVOID释放
    m_itrPacket = m_mapPacketList.find(lPacketKey); if(m_itrPacket == m_mapPacketList.end())
    {
    return 1;
    }

    free(((SCK_PACKET)((*m_itrPacket).second)).lpPacketBody_Whole);

    m_mapPacketList.erase(lPacketKey);
    return 0;
    }//其中m_mapPacketList是用来保存这些数据包的map,
    //m_itrPacket是用来查询这个map的iterator.上面的程序编译没错.就不知道有没有真正释放掉这块内存.