max*_*lon 3 c c++ sockets networking winsock
我做了自己的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;
}
Run Code Online (Sandbox Code Playgroud)
有没有人看到任何可能导致崩溃的事情,或者有没有人有更好/更快/更小和更稳定的例子如何通过recv()接收完整数据包?
我不能使用字符串,但必须使用字符.
谢谢你的帮助.
你没有初始化temp,最重要的是,你的呼叫realloc是错误的.它应该是:
temp = realloc (temp, recvsize+1);
Run Code Online (Sandbox Code Playgroud)
当你打电话给realloc你时,你扔掉了新地址,很可能现在已经释放了旧地址.当你试图取消引用时,所有的赌注都会被取消.
realloc返回新地址的原因是因为如果当前块在存储器区域中被包围(换句话说,它不能仅扩展到跟随它的空闲块),则缓冲器的扩展可能需要移动它.在这种情况下,将在场地中创建一个新块,从旧块传输的内容和旧块被释放.如果realloc发生这种情况,你必须得到返回值.
请记住,realloc不具备返回一个新的指针,它可以给你同样的指针,如果,例如,有足够的自由空间块之后,以满足新的大小或者如果你缩小尺寸.
如果它不能扩展块,它也可以返回NULL,你应该注意它,特别是因为:
temp = realloc (temp, newsize);
Run Code Online (Sandbox Code Playgroud)
当它返回NULL时会导致内存泄漏(它不会释放旧块).
其他一些事情:
calloc,特别是在这种情况下,因为你无论如何都要复制内存.memset如果您立即将内存块更改为0,则不需要将内存块设置为0 memcpy.temp到NULL,你可以使用realloc没有测试它.这是因为realloc(NULL,7)是相同的malloc(7)- realloc是完全能够与一个空指针开始的.calloc,这是唯一的教育- sizeof(char)是永远 1定义.为什么我们不从一些更简单的东西开始?现在,这完全是出于我的想法,所以可能存在一些错误,但它至少会从问题中的内存移动庞然大物中减少:-)所以应该更容易调试.
它基本上分解为:
代码看起来像这样:
int Socket::Recv(char *&vpszRecvd) {
int recvsize = 0;
char TempBuf[1024];
int Result = 0;
char *oldPtr;
// Optional free current and initialise to empty.
//if (vpszRecvd != NULL) free (vpszRecvd);
vpszRecvd = NULL;
// Loop forever (return inside loop on end or error).
do {
Result = recv( this->sSocket, TempBuf, sizeof(TempBuf) -1, 0 );
// Free memory, close socket on error.
if (Result < 0) {
free (vpszRecvd);
closesocket(this->sSocket);
this->sSocket = INVALID_SOCKET;
return SOCKET_ERROR;
}
// Just return data and length on end.
if (Result == 0) {
return recvsize;
}
// Have new data, use realloc to expand, even for initial malloc.
oldPtr = vpszRecvd;
vpszRecvd = realloc (vpszRecvd, recvsize + Result);
// Check for out-of-memory, free memory and return 0 bytes.
if (vpszRecvd == NULL) {
free (oldPtr);
return 0;
}
// Append it now that it's big enough and adjust the size.
memcpy (&(vpszRecvd[recvsize], TempBuf, Result);
recvsize += Result;
} while (1);
}
Run Code Online (Sandbox Code Playgroud)