我要做一个通过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的内存释放呢?
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的内存释放呢?
你应该在SCK_PACKET内记录LPVOID所指响的内存的大小,然后用free来释放。
当然,分配是用malloc,释放时用free。
只是我的愚见,指教一下。
先回答这个
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就可以。
但同样需要类型转换,用boost的any_cast<>()
最主要是你必须记得map内的每个对象的真正类型是什么,不然的话你无法进行类型转换
ps:
jvm和clr是如何的强大,来个反射不就搞定了。
你应该在SCK_PACKET内记录LPVOID所指响的内存的大小
其实这个不需要记录,因为free不需要指定大小,而malloc是需要的。
给个例子:
void* p = malloc(sizeof(MsgBindResp));
//这里可以强制类型转换
MsgBindResp * pBindResp = (MsgBindResp *)p;
//这里做你应该做的事
//删除一个数据包//参数: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.上面的程序编译没错.就不知道有没有真正释放掉这块内存.