C++ C++;-TCP套接字类:接收问题
我做了自己的套接字类,以便能够发送和接收HTTP请求。 但我还是有一些问题。下面的代码(我的接收函数)仍然有缺陷,有时会崩溃。 我试着调试它,但它一定在指针算术/内存管理的某个地方C++ C++;-TCP套接字类:接收问题,c++,c,networking,sockets,winsock,C++,C,Networking,Sockets,Winsock,我做了自己的套接字类,以便能够发送和接收HTTP请求。 但我还是有一些问题。下面的代码(我的接收函数)仍然有缺陷,有时会崩溃。 我试着调试它,但它一定在指针算术/内存管理的某个地方 int Socket::Recv(char *&vpszRecvd) { //vpszRecvd = NULL; int recvsize = 0; char TempBuf[1024]; int Result = 0; char* temp; do { memset(TempBuf
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()接收完整数据包
我不能使用字符串,但必须使用字符
谢谢你的帮助。我最近遇到了这个问题 Realloc很慢。Recv速度很快。每秒几百个realloc将崩溃 calloc()不仅仅是recvsize+1,还有一个额外的几千字节的缓冲区。只有当缓冲区被填满/溢出时,才使用realloc(),并在每个realloc()上再多给它几KB 下面是我用来将数据附加到输出流中的一段代码,但输入应该非常相似。(请注意,buf_out_size是已分配缓冲区的大小,buf_out_len是缓冲区中当前的数据量。)
您没有初始化
temp
,除此之外,您对realloc
的调用是错误的。应该是:
temp = realloc (temp, recvsize+1);
当您按原样调用realloc
时,您会丢弃新地址,很有可能旧地址现在已被释放。当你尝试去引用它时,所有的赌注都被取消了
realloc
返回新地址的原因是,如果当前块在内存区域中被包围,则扩展缓冲区可能需要移动缓冲区(换句话说,它不能扩展为紧跟其后的空闲块)。在这种情况下,将在竞技场中创建一个新块,从旧块传输的内容将被释放。如果发生这种情况,您必须从realloc
获取返回值
请记住,realloc
不必返回新指针,例如,如果块后有足够的可用空间来满足新的大小,或者如果您正在减小大小,它可能会给您相同的指针
如果无法扩展块,它也可能返回NULL,您也应该注意这一点,特别是因为:
temp = realloc (temp, newsize);
当它返回NULL时将导致内存泄漏(它不会释放旧块)
还有几件事:
- 您很少需要使用
,尤其是在这种情况下,因为您仍然在内存上进行复制calloc
- 类似地,如果要立即在内存块上执行
,则不需要memcpy
将内存块设置为0memset
- 如果您将
初始化为temp
,则只需使用NULL
,而无需对其进行测试。这是因为realloc
与realloc(NULL,7)
-malloc(7)
完全能够以NULL指针开始realloc
- 由于您不需要
,因此这仅用于教育-calloc
根据定义始终为1sizeof(char)
- 您似乎正在进行大量不必要的数据复制
我们为什么不从简单一点的开始呢?现在,这完全是我的想法,所以可能会有一些错误,但它至少是从问题中移动内存的庞然大物中删除的:-),所以应该更容易调试 基本上分为:
- 初始化空消息
- 进入无限循环。
- 获取片段
- 如果发生错误,请释放所有内容并返回错误
- 如果没有更多的段,则返回当前消息
- 在消息末尾为新段创建空间
- 如果无法创建空间,请释放所有内容并返回空消息
- 将段附加到消息并调整消息大小
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);
}
intsocket::Recv(char*&vpszRecvd){
int recvsize=0;
char TempBuf[1024];
int结果=0;
char*oldPtr;
//可选自由电流和初始化为空。
//如果(vpszRecvd!=NULL)空闲(vpszRecvd);
vpszRecvd=NULL;
//永远循环(结束时返回内部循环或错误)。
做{
结果=recv(此->sSocket,TempBuf,sizeof(TempBuf)-1,0;
//释放内存,错误时关闭套接字。
如果(结果<0){
免费(vpszRecvd);
闭合插座(此->闭合插座);
此->sSocket=无效的\u套接字;
返回套接字错误;
}
//只需在末尾返回数据和长度。
如果(结果==0){
返回recvsize;
}
//拥有新数据,使用realloc进行扩展,即使是初始malloc。
oldPtr=vpszRecvd;
vpszRecvd=realloc(vpszRecvd,recvsize+结果);
//检查内存是否不足,释放内存并返回0字节。
如果(vpszRecvd==NULL){
免费(oldPtr);
返回0;
}
//现在它已经足够大了,可以附加它并调整大小。
memcpy(&(vpszRecvd[recvsize],TempBuf,Result);
recvsize+=结果;
}而(1),;
}
听起来不错。有没有示例代码?我想我的代码有很多漏洞,有几个东西会崩溃。我甚至找不到一个接收代码,基于字符,可以接收整个数据包。为什么要让几百个realloc再次崩溃?呃,我不这么认为,@SF.TCP实际上会等你,如果你不够快的话。Recv也一样快不管怎样,我添加了一些额外的字节,它不再崩溃,而是返回空字符数组或纯b_llshit…@maxedmelon,它返回的是牛粪(正如你雄辩地说的那样),因为realloc-见我的答案。memcpy(vpszRecvd,TempBuf,Result);我现在就编辑它。它有一个C++
标记。因此,您可以使用std::vector
作为缓冲区来摆脱所有内存问题。使用其resize()
成员函数来设置其大小并使用
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);
}