C++ 套接字下载的网页太少或太多

C++ 套接字下载的网页太少或太多,c++,sockets,winsock2,C++,Sockets,Winsock2,为什么我的代码只下载了半个网页??有时它会下载4倍于网页大小的文件:s 我找不到哪里出了问题,这就是我为什么要问的原因。基本上,我连接到套接字,发送请求并将响应读取到缓冲区。我试着将它保存到一个文件并打印到屏幕上,但它打印并保存了不完整的数据或太多的数据。我不确定这是否是缓冲区溢出,或者我做错了什么 有什么想法吗 #define _WIN32_WINNT 0x501 #include <iostream> #include <winsock2.h> #include &

为什么我的代码只下载了半个网页??有时它会下载4倍于网页大小的文件: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");
}
#定义_WIN32_WINNT 0x501
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
无效获取(字符串网页)
{
WSADATA WSADATA;
字符串地址;
结构addrinfo*结果;
*sockaddr_ipv4中的结构sockaddr_;
字符缓冲区[50000]={0};
string Header=“GET/HTTP/1.1\r\n”;
标题+=“主机:”+WebPage+“\r\n”;
标头+=“连接:关闭\r\n”;
标题+=“\r\n”;
if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)返回;
SOCKET SOCKET=SOCKET(AF\u INET、SOCK\u STREAM、IPPROTO\u TCP);
getaddrinfo(WebPage.c_str(),NULL,NULL和result);
如果(结果->ai_族==AF_INET)
{
sockaddr_ipv4=(结构sockaddr_in*)结果->ai_地址;
地址=inet\u ntoa(sockaddr\u ipv4->sin\u addr);
}
freeaddrinfo(结果);
SOCKADDR_在SOCKADDR中;
memset(&SockAddr,0,sizeof(SockAddr));
SockAddr.sinu端口=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\u ERROR)返回;
if(send(Socket,Header.c_str(),Header.size(),0)=Socket_ERROR)返回;
关机(插座、SD_发送);
字符串响应;
while(true)
{
int Val=recv(Socket,Buffer,sizeof(Buffer),0);
如果(Val==0)
打破
else if(Val==SOCKET\u错误)
{

coutEdit:recv为您终止数据不是空的-您需要写入您收到的数据量,而不仅仅是+=它


您的回复中是否有任何二进制数据?如果有,则

Response += Buffer;
将在第一个空字符处停止。我将使用向量存储recv中的数据,如下所示:

vector<char> recvBuffer(50000);

int bytesReceived = recv(socket, recvBuffer.data(), recvBuffer.size(), 0);
//error checking
recvBuffer.resize(bytesReceived);
vector recvBuffer(50000);
int bytesReceived=recv(套接字,recvBuffer.data(),recvBuffer.size(),0);
//错误检查
recvBuffer.resize(字节接收);
然后再次将接收到的数据存储在另一个向量中,并将其复制回

vector<char> pageContents;

pageContents.insert(pageContents.end(), recvBuffer.begin(), recvBuffer.end());
矢量页面内容;
插入(pageContents.end(),recvBuffer.begin(),recvBuffer.end());
但这并不能解释你的4x数据

我看到的另一个问题是,在使用缓冲区之后,您没有将其归零


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

编辑:recv不是空的,为您终止数据-您需要写入接收的数据量,而不仅仅是+=数组


您的回复中是否有任何二进制数据?如果有,则

Response += Buffer;
将在第一个空字符处停止。我将使用向量存储recv中的数据,如下所示:

vector<char> recvBuffer(50000);

int bytesReceived = recv(socket, recvBuffer.data(), recvBuffer.size(), 0);
//error checking
recvBuffer.resize(bytesReceived);
vector recvBuffer(50000);
int bytesReceived=recv(套接字,recvBuffer.data(),recvBuffer.size(),0);
//错误检查
recvBuffer.resize(字节接收);
然后再次将接收到的数据存储在另一个向量中,并将其复制回

vector<char> pageContents;

pageContents.insert(pageContents.end(), recvBuffer.begin(), recvBuffer.end());
矢量页面内容;
插入(pageContents.end(),recvBuffer.begin(),recvBuffer.end());
但这并不能解释你的4x数据

我看到的另一个问题是,在使用缓冲区之后,您没有将其归零


IOW:你需要写下你收到了多少数据,而不仅仅是+=数组。

Ahh这起作用了。它也修复了4x数据。我需要添加的只是:缓冲区[Val]='\0';但我最终将其更改为您建议的向量。谢谢。现在唯一的问题是,有时它会向文件中添加额外的符号或数字。我猜它是以块的形式下载页面的,可能是块的长度。但我不知道如何停止。如果您要解析HTTP响应,您会想要失败k与规格非常接近。+1,但不必“调零”整个缓冲区,也不必使用2个向量。只需在循环之前使用
int len=0;
,然后在循环内部使用
recvBuffer.resize(len+50000);int bytesReceived=recv(socket,&recvBuffer[0]+len,recvBuffer.size()-len,0);len+=bytesReceived;
(另外请注意,
data()
仅在C++1x中引入;
&recvBuffer[0]+len
保证在C++03和C++1x中都能工作。)啊,这很有效。它也修复了4x数据。我需要添加的只是:缓冲区[Val]='\0';但我最终将其更改为您建议的向量。谢谢。现在唯一的问题是,有时它会向文件中添加额外的符号或数字。我猜它是以块的形式下载页面的,可能是块的长度。但我不知道如何停止。如果您要解析HTTP响应,您会想要失败k与规格非常接近。+1,但不必“调零”整个缓冲区,也不必使用2个向量。只需在循环之前使用
int len=0;
,然后在循环内部使用
recvBuffer.resize(len+50000);int bytesReceived=recv(socket,&recvBuffer[0]+len,recvBuffer.size()-len,0);len+=bytesReceived;
(另外请注意,
data()
仅在C++1x中引入;
&recvBuffer[0]+len
保证在C++03和C++1x中都能工作)。