我正在尝试使用 Winsock2 的 HTTP 协议。我正在研究一个功能
int recv_data(const char *hostname, char *resp);
该函数旨在向给定主机发送 HTTP HEAD 请求,然后接收响应。它在指针 resp 处分配内存并在那里复制响应,然后返回为响应接收的总字节数。
这是我的接收循环:
int recv_data(const char *hostname, char *resp)
{
int totalRecvd = 0;
stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
resp = new char[totalRecvd + 1];
strcpy(resp, sStream.str().c_str());
return totalRecvd);
}
所有这些工作都很好,如果我此时输出 resp,它输出就好了。如果我在函数明显返回后尝试输出 resp,我就会遇到问题。我不相信这应该是正常的事情,如果我没记错的话,我相信这与我使用 stringstream 临时存储响应有关。我想我在某处读到过有关 stringstream 收集的数据超出范围的信息。
我希望我可以以这种方式设置这个函数,调用者可以只传入一个 char* 并且该函数将分配正确的内存量(在运行时根据主机和返回的字节数确定) recv(). 无论如何,我是否可以从内存中的字符串流作为 char 数组获取永久副本,并且在函数返回并且字符串流超出范围后指针变坏?
[编辑]:下面是我的问题中发布的解决方案,任何希望将其重用于 Winsock2 编程的人都可以使用它,似乎效果很好。当 recv() 返回 0 时,将从服务器接收数据,直到连接关闭。解决方案是传入对指针的引用,因为 new 运算符会更改指针,并且该更改不会在函数返回后反映,除非它被传递通过参考。
int recv_data(SOCKET s, char *&data)
{
int totalRecvd = 0;
std::stringstream sStream;
while (true)
{
char buffer[MAX_HEADER_SIZE];
int retValue = recv(s, buffer, MAX_HEADER_SIZE, 0);
if (retValue == 0)
break; // connection has been closed
else if (retValue == SOCKET_ERROR)
throw RecvException("http_headreq() unable to receive data");
else //
{
buffer[retValue] = 0; // append null terminator
sStream << buffer; // dump buffer into stream
totalRecvd += retValue + 1; // tally received bytes
}
}
/** Allocate and read entire read stream into memory */
data = new char[totalRecvd + 1];
strcpy_s(data, totalRecvd, sStream.str().c_str());
data[totalRecvd] = 0;
return totalRecvd;
}