C C++ - TCP 套接字类:接收问题
我创建了自己的 Socket 类,以便能够发送和接收 HTTP 请求。 但我仍然遇到一些问题。下面的代码(我的接收函数)仍然有错误,有时会崩溃。 我尝试调试它,但它一定在指针算术/内存管理中的某个地方。
int Socket::Recv(char *&vpszRecvd)
{
//vpszRecvd = NULL;
int recvsize = 0;
char TempBuf[1024];
int Result = 0;
char* temp;
do
{
memset(TempBuf, 0, sizeof(TempBuf));
Result = recv( this->sSocket, TempBuf, sizeof(TempBuf) -1, 0 );
if (recvsize == 0)
recvsize = Result;
if ( Result > 0 )
{
if ( vpszRecvd != NULL )
{
if (temp == NULL)
{
temp = (char*)calloc(recvsize + 1, sizeof(char));
}
else
{
realloc(temp, recvsize + 1);
}
if (temp == NULL)
return 0;
memcpy(temp, vpszRecvd, recvsize);
realloc(vpszRecvd, recvsize + Result);
if (vpszRecvd == NULL)
return 0;
memset(vpszRecvd, 0, recvsize + Result);
memcpy(vpszRecvd, TempBuf, Result);
memcpy(vpszRecvd + recvsize, TempBuf, Result);
recvsize += Result;
}
else
{
realloc(vpszRecvd, Result);
if (vpszRecvd == NULL)
return 0;
memset(vpszRecvd, 0, Result);
memcpy(vpszRecvd, TempBuf, Result);
recvsize += Result;
}
}
else if ( Result == 0 )
{
return recvsize;
}
else //if ( Result == SOCKET_ERROR )
{
closesocket(this->sSocket);
this->sSocket = INVALID_SOCKET;
return SOCKET_ERROR;
}
}
while( Result > 0 );
return recvsize;
}
有没有人看到任何可能导致崩溃的东西,或者有没有人有更好/更快/更小且稳定的示例如何通过 recv() 接收完整的数据包?
我不能使用字符串,但必须使用字符来完成。
感谢您的帮助。
I did my own Socket class, to be able to send and receive HTTP requests.
But I still got some problems. The following code (my receive function) is still buggy, and crashing sometimes.
I tried debugging it, but it must be somewhere in the pointer arithmetics / memory management.
int Socket::Recv(char *&vpszRecvd)
{
//vpszRecvd = NULL;
int recvsize = 0;
char TempBuf[1024];
int Result = 0;
char* temp;
do
{
memset(TempBuf, 0, sizeof(TempBuf));
Result = recv( this->sSocket, TempBuf, sizeof(TempBuf) -1, 0 );
if (recvsize == 0)
recvsize = Result;
if ( Result > 0 )
{
if ( vpszRecvd != NULL )
{
if (temp == NULL)
{
temp = (char*)calloc(recvsize + 1, sizeof(char));
}
else
{
realloc(temp, recvsize + 1);
}
if (temp == NULL)
return 0;
memcpy(temp, vpszRecvd, recvsize);
realloc(vpszRecvd, recvsize + Result);
if (vpszRecvd == NULL)
return 0;
memset(vpszRecvd, 0, recvsize + Result);
memcpy(vpszRecvd, TempBuf, Result);
memcpy(vpszRecvd + recvsize, TempBuf, Result);
recvsize += Result;
}
else
{
realloc(vpszRecvd, Result);
if (vpszRecvd == NULL)
return 0;
memset(vpszRecvd, 0, Result);
memcpy(vpszRecvd, TempBuf, Result);
recvsize += Result;
}
}
else if ( Result == 0 )
{
return recvsize;
}
else //if ( Result == SOCKET_ERROR )
{
closesocket(this->sSocket);
this->sSocket = INVALID_SOCKET;
return SOCKET_ERROR;
}
}
while( Result > 0 );
return recvsize;
}
Does anybody see anything that could cause the crash, or does anyone have a better / faster / smaller and stable example how to receive a full packet via recv()?
I can't use strings, it must be done with chars, though.
Thanks for your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您没有初始化
temp
,最重要的是,您对realloc
的调用是错误的。应该是:当您像以前那样调用 realloc 时,您会丢弃新地址,并且旧地址现在很可能已被释放。当您尝试取消引用它时,所有的赌注都会消失。
realloc 返回新地址的原因是,如果当前块被内存区域包围,则缓冲区的扩展可能需要移动它(换句话说,它不能只是扩展为空闲块)跟随它)。在这种情况下,将在竞技场中创建一个新块,从旧块传输内容并释放旧块。如果发生这种情况,您必须从
realloc
获取返回值。请记住,
realloc
没有返回新指针,它可能会为您提供相同的指针,例如,如果块后有足够的可用空间满足新尺寸或者您正在减小尺寸。如果它无法扩展块,它也可以返回 NULL,您也应该注意这一点,特别是因为:
当它返回 NULL 时会导致内存泄漏(它不会释放旧块)。
其他一些事情:
memcpy
,则无需将内存块memset
设置为0。temp
初始化为NULL
,则可以直接使用realloc
而无需对其进行测试。这是因为realloc(NULL,7)
与malloc(7)
相同 -realloc
完全能够以空指针开头。calloc
,这仅用于教育目的 - 根据定义,sizeof(char)
始终 1。我们为什么不从简单一点的事情开始呢?现在,这完全是我的想法,所以可能存在一些错误,但它至少从问题中的内存移动庞然大物中减少了:-)所以应该更容易调试。
它基本上分为:
代码如下所示:
You don't initialise
temp
and, on top of that, your call torealloc
is wrong. It should be:When you call
realloc
as you have, you throw away the new address and there's a good chance that the old address has now been freed. All bets are off when you then try to dereference it.The reason
realloc
returns a new address is because expansion of the buffer may necessitate it being moved if that current block is surrounded in the memory arena (in other words, it can't just expand into a free block following it). In that case, a new block will be created in the arena, the contents transferred from the old block and the old block freed. You have to get the return value fromrealloc
in case that happens.Keep in mind that
realloc
doesn't have to return a new pointer, it may give you the same pointer if, for example, there was enough free space after the block to satisfy the new size or if you're reducing the size.It can also return NULL if it can't expand the block, you should watch out for that as well, especially since:
will result in a memory leak when it returns NULL (it doesn't free the old block).
A few other things:
calloc
, especially in this case since you're copying over the memory anyway.memset
a memory chunk to 0 if you're immediately going tomemcpy
over it.temp
toNULL
, you can just userealloc
without testing it. That's becauserealloc(NULL,7)
is identical tomalloc(7)
-realloc
is perfectly capable of starting with a null pointer.calloc
, this is for education only -sizeof(char)
is always 1 by definition.Why don't we start with something a bit simpler? Now, this is totally from my head so there may be some bugs but it's at least cut down from the memory-moving behemoth in the question :-) so should be easier to debug.
It's basically broken down into:
and the code looks like this:
我最近遇到了这个问题。
重新分配很慢。接收速度很快。每秒数百次重新分配将会崩溃。
calloc() 不只是recvsize + 1,而且还额外增加了几千字节的缓冲区。仅当缓冲区被填充/溢出时才调用 realloc(),并在每个 realloc() 上额外提供几千字节。
下面是我用来将数据附加到输出流的一段代码,但输入应该非常相似。 (请注意,buf_out_size 是分配的缓冲区的大小,buf_out_len 是缓冲区中当前的数据量。)
I had this exact problem very recently.
Realloc is slow. Recv is fast. Several hundred reallocs a second WILL crash.
calloc() not just recvsize + 1 but a buffer of a couple kilobytes extra. realloc() only when the buffer would be filled/overflow, and give it another few kilobytes extra on each realloc().
the below is a piece of code I use to append data to my output stream, but input should be very similar. (as a note, buf_out_size is the size of allocated buffer, buf_out_len is the amount of data currently in the buffer.)