2012-11-16 114 views
0

为什么我的代码只下载半个网页?有时它下载4x的网页大小:S套接字下载太少或太多的网页

我找不到这是什么问题,这就是为什么我问。基本上,我连接到套接字,发送我的请求并读取响应缓冲区。我试着将它保存到一个文件并将其打印到屏幕上,但它会打印并保存不完整的数据或太多的数据。我不确定是否它的缓冲区溢出或者我做错了什么。

任何想法?

#define _WIN32_WINNT 0x501 

#include <iostream> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#include <stdio.h> 
#include <fstream> 

using namespace std; 

void Get(string WebPage) 
{ 
    WSADATA wsaData; 
    string Address; 
    struct addrinfo *result; 
    struct sockaddr_in *sockaddr_ipv4; 

    char Buffer[50000] = {0}; 

    string Header = "GET/HTTP/1.1\r\n"; 
    Header += "Host: " + WebPage + "\r\n"; 
    Header += "Connection: close\r\n"; 
    Header += "\r\n"; 

    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) return; 

    SOCKET Socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 

    getaddrinfo(WebPage.c_str(), NULL, NULL, &result); 
    if (result->ai_family == AF_INET) 
    { 
     sockaddr_ipv4 = (struct sockaddr_in *) result->ai_addr; 
     Address = inet_ntoa(sockaddr_ipv4->sin_addr); 
    } 
    freeaddrinfo(result); 


    SOCKADDR_IN SockAddr; 
    memset(&SockAddr, 0, sizeof(SockAddr)); 
    SockAddr.sin_port = htons(80); 
    SockAddr.sin_family = AF_INET; 
    SockAddr.sin_addr.s_addr = inet_addr(Address.c_str()); 

    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) == SOCKET_ERROR) return; 

    if (send(Socket, Header.c_str(), Header.size(), 0) == SOCKET_ERROR) return; 
    shutdown(Socket, SD_SEND); 

    std::string Response; 

    while(true) 
    { 
     int Val = recv(Socket, Buffer, sizeof(Buffer), 0); 
     if (Val == 0) 
      break; 
     else if (Val == SOCKET_ERROR) 
     { 
      cout<<"Error!"; 
     } 
     else 
     { 
      Response += Buffer; 
     } 
    } 

    closesocket(Socket); 
    WSACleanup(); 

    ofstream File; 
    File.open("C:/Saved.html"); 
    File<<Response; 
    File.close(); 
} 

int main() 
{ 
    Get("villavu.com"); 
} 

回答

3

编辑:recv不是null为你终止数据 - 你需要写出你收到多少数据,而不仅仅是+ =它。


是否有您回应任何二进制数据?如果是这样,

Response += Buffer; 

将停在第一个空字符。我会用一个载体来存储数据从recv的这样:

vector<char> recvBuffer(50000); 

int bytesReceived = recv(socket, recvBuffer.data(), recvBuffer.size(), 0); 
//error checking 
recvBuffer.resize(bytesReceived); 

,并再次将接收到的数据存储在另一个载体,复制它放回

vector<char> pageContents; 

pageContents.insert(pageContents.end(), recvBuffer.begin(), recvBuffer.end()); 

这不能解释你的4倍数据。

我看到的另一个问题是,在使用缓冲区之后,您并未清零您的缓冲区。

IOW:您需要写出您接收的数据量,而不仅仅是+ =数组。

+0

啊,这工作。它也修复了4倍数据。 所有我不得不补充的是: Buffer [Val] ='\ 0'; 但我最终改变它像一个你建议的载体。谢谢。 现在唯一的问题是,它有时会为文件添加额外的符号或数字。我猜想它是以块的形式下载页面的,而且可能是块的长度。不知道如何阻止。 – Brandon

+0

如果你打算解析HTTP响应,你会想要仔细看看这个规范。 –

+0

+1,但没有必要“清零”整个缓冲区,或者使用2个向量。你可以在循环之前使用'int len = 0;'然后'recvBuffer.resize(len + 50000); int bytesReceived = recv(socket,&recvBuffer [0] + len,recvBuffer.size() - len,0); (注意'data()'仅在C++ 1x中引入;'&recvBuffer [0] + len'保证可以在C++ 03和C++ 1x中工作) 。 –