我有一个简单的函数,允许我在服务器上获取文件的内容。它的工作方式与我想要的方式但是 “Visual Leak Detector”指出行closeSocket(...)
上存在内存泄漏。
以下代码:
string executeUrl(const char *url)
{
SOCKET sConnection;
char szHeader[500];
sprintf(szHeader, "GET %s HTTP/1.0\r\n"
"Host: %s\r\n"
"User-Agent: Agent\r\n"
"\r\n", url, HTTPSERVER);
sConnection = HTTPConnectToServer(HTTPSERVER);
if (sConnection == 0)
{
return "";
}
send(sConnection, szHeader, strlen(szHeader), 0);
char reply[1024];
ZeroMemory(reply, 1024);
if (recv(sConnection, reply, 1024, 0) == SOCKET_ERROR)
{
return "";
}
string returnString(reply);
closesocket(sConnection);
WSACleanup();
return returnString;
}
泄漏的数据字符串returnString
。所以它与字符串相关或与closesocket()
相关。
我做了一些阅读,我无法弄清楚。显然字符串应该自己处理并且不会导致内存泄漏,是吗?
编辑:
我尝试了以下代码:http://www.zedwood.com/article/cpp-winsock-basic-http-connection
即使这段代码也会给我带来内存泄漏。我还测试了一个不同的应用程序(Deleaker),它也告诉我存在相同的内存泄漏。
EDIT2:
刚刚发现它不是唯一一次字符串泄漏内存。这段代码也是一个问题:
urlString = (string)"http://someurl" + std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(pcName) + (string)"somefile.php";
泄露的数据显然是“urlString”所持有的。我完全糊涂了。
答案 0 :(得分:2)
我希望有一些未定义的行为。您已阅读1024个字符进行回复。然后使用期望以null结尾的字符序列的构造函数。你怎么能确定回复是以空字符结尾的字符序列?
作为快速测试,请尝试阅读1023个字符而不是1024个,这里:
if (recv(sConnection, reply, 1023, 0) == SOCKET_ERROR)
答案 1 :(得分:2)
当您从插座阅读时,您不应该假设您已经在一次阅读中收到了所有数据。
在这种情况下,服务器可能已经发送了超过1024个字节并且您正好读取了1024.这里可能发生的是您的缓冲区不会以NULL结尾,并且您尝试使用它初始化字符串并且没有给它正确长度。 Afaik这是未定义的行为,因此它是您可能想要解决的第一件事。此外,您应该阅读服务器发送的所有数据。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<mode>development</mode>
<url>http://sample.com</url>
<key>value</key>
</manifestEntries>
</archive>
</configuration>
</plugin>
修改:此代码错误。如果没有与服务器预先交换消息,则很难确定消息应该有多少字节或内容。对于此代码,如果服务器正好发送1024个字节,则char reply[1025];
ZeroMemory(reply, 1025);
string returnString;
int val = 0;
do
{
val = recv(sConnection, reply, 1024, 0);
if (val == SOCKET_ERROR)
{
// Treat errors
}
strcat (returnString, reply);
ZeroMemory(reply, 1025);
}
while (val == 1024);
将在下一次迭代时被阻止,因为没有任何内容可读。
网络协议建立这些基本通信规则。例如,http协议规定消息的第一部分由头部组成,每个头部以CRLF对结束,头部的末端由2个CRLF对标记。为了使我的代码正确,我将不得不解析标题并提取Content-Length值,然后读取消息正文,直到达到指定的长度。
答案 2 :(得分:1)
此代码包含潜在的缓冲区溢出,您应该使用字符串构造函数:
string returnString(reply, 1024);
您正在使用的构造函数假定它正在传递一个以空字符结尾的字符串,根据recv()的结果可能不是这种情况。
编辑:closesocket的返回值是多少?在程序终止之前,您确定套接字实际上已关闭吗?如果你在closesocket调用和结束函数之间等待几秒钟会发生什么?
答案 3 :(得分:0)
最好从MSDN中获取一些示例代码,即:
https://msdn.microsoft.com/pl-pl/library/windows/desktop/ms737591(v=vs.85).aspx
或者至少尝试运行此示例以检查它是否也会导致泄漏。
我发现你错过了shutdown电话,是否可能导致泄密 - 我不确定,从你的文档中你可以读到:
为了确保所有数据在关闭之前在连接的套接字上发送和接收,应用程序应该在调用closesocket之前使用shutdown来关闭连接。
顺便说一句。使用Win API时,请始终检查可能从api函数返回的所有错误代码。