Простой HTTP Get с помощью Winsock

#c #http #winsock

#c #http #winsock

Вопрос:

Некоторое время назад я создал очень простой метод, который мог бы отправлять http-запрос и возвращать ответ. Это сработало так, как я намеревался, но теперь я хочу использовать его снова, но я внезапно столкнулся с проблемой, которую, похоже, не могу понять. Каждый раз, когда я делаю запрос, он возвращает ошибку 503: служба недоступна.

Иногда это работает, иногда нет.

Я заметил, что если я поставлю точку останова после завершения соединения и немного подожду и продолжу, проблем нет, и все работает. Итак, я предполагаю, что это как-то связано с синхронизацией / задержкой сервера.

У кого-нибудь есть опыт работы с этим?

Заранее спасибо!

 string HttpHelper::HttpGet(string host, string path)
{
    WSADATA wsaData;
    int resu<

    // Initialize Winsock
    result = WSAStartup(MAKEWORD(2, 2), amp;wsaData);
    if (result != 0)
        throw SocketError(L"WSAStartUp", result);

    // Resolve the server address and port
    addrinfo * pAddrInfo;
    result = getaddrinfo(host.c_str(), "80", 0, amp;pAddrInfo);
    if (result != 0)
        throw SocketError(L"addrinfo", result);

    //Create the socket
    SOCKET sock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);

    if (sock == INVALID_SOCKET)
        throw SocketError(L"Socket", WSAGetLastError());

    // Connect to server.
    result = connect(sock, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen);
    if (result != 0)
        throw SocketError(L"Connect", WSAGetLastError());

    const string request = "GET "   path   " HTTP/1.1nHost: "   host   "nn";

    // Send an initial buffer
    result = send(sock, request.c_str(), request.size(), 0);
    if (result == SOCKET_ERROR)
        throw SocketError(L"Send", WSAGetLastError());

    // shutdown the connection since no more data will be sent
    result = shutdown(sock, SD_SEND);
    if (result == SOCKET_ERROR)
        throw SocketError(L"Close send connection", WSAGetLastError());

    // Receive until the peer closes the connection
    string response;

    char buffer[50];
    int bytesRecv = 0;

    for (;;)
    {
        result = recv(sock, buffer, sizeof(buffer), 0);
        if (result == SOCKET_ERROR)
            throw SocketError(L"Recv", WSAGetLastError());
        if (result == 0)
            break;
        response  = string(buffer, result);
        wstringstream stream;
        stream << L"HttpGet() > Bytes received: " << bytesRecv;
        DebugLog::Log(stream.str(), LogType::INFO);
        bytesRecv  = resu<
    }
    wstringstream stream;
    stream << L"HttpGet() > Bytes received: " << bytesRecv;
    DebugLog::Log(stream.str(), LogType::INFO);

    // cleanup
    result = closesocket(sock);
    if (result == SOCKET_ERROR)
        throw SocketError(L"Closesocket", WSAGetLastError());

    result = WSACleanup();
    if (result == SOCKET_ERROR)
        throw SocketError(L"WSACleanup", WSAGetLastError());

    freeaddrinfo(pAddrInfo);

    DebugLog::Log(L"HttpGet() > Cleanup Successful ", LogType::INFO);

    return response;
}

wstring SocketError::ErrorMessage(const wstring amp; context, const int errorCode) const
{
    wchar_t buf[1024];
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, buf, sizeof(buf), 0);
    wchar_t * newLine = wcsrchr(buf, 'r');
    if (newLine) *newLine = '';
    wstringstream stream;
    stream << L"Socket error in " << context << L" (" << errorCode << L"): " << buf;
    return stream.str();
}
  

Комментарии:

1. Разве возврат каретки не является обязательным?

2. @Marichyasana пожалуйста, не будь противным. Вопросы приветствуются на этой платформе.

3. Вы должны проверить, что send возвращено то же количество байтов, request.c_str() что и . Если нет, выполняйте цикл до тех пор, пока не будут отправлены все байты из строки запроса.

4. Завершитель строки в HTTP определяется как rn , а не как n .

5. Вам удалось найти решение?

Ответ №1:

Трудно сказать…

Вот простой и общий фрагмент кода winsock, который вы можете попробовать, просто чтобы посмотреть, существует ли проблема при использовании этого кода.

 #include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")


string website_HTML;
locale local;
void get_Website(string url );
char buffer[10000];
int i = 0 ;


 //****************************************************

int main( void ){

    get_Website("www.stackoverflow.com" );

    cout<<website_HTML;

    cout<<"nnPress ANY key to close.nn";
    cin.ignore(); cin.get(); 


 return 0;
}

 //****************************************************

void get_Website(string url ){
    WSADATA wsaData;
    SOCKET Socket;
    SOCKADDR_IN SockAddr;
    int lineCount=0;
    int rowCount=0;
    struct hostent *host;
    string get_http;


    get_http = "GET / HTTP/1.1rnHost: "   url   "rnConnection: closernrn";

    if (WSAStartup(MAKEWORD(2,2), amp;wsaData) != 0){
        cout << "WSAStartup failed.n";
        system("pause");
        //return 1;
    }

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    host = gethostbyname(url.c_str());

    SockAddr.sin_port=htons(80);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

    if(connect(Socket,(SOCKADDR*)(amp;SockAddr),sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        //return 1;
    }
    send(Socket,get_http.c_str(), strlen(get_http.c_str()),0 );

    int nDataLength;
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){        
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == 'n' || buffer[i] == 'r'){

            website_HTML =buffer[i];
            i  = 1;
        }               
    }

    closesocket(Socket);
    WSACleanup();

}
  

Ответ №2:

Вы должны отправить его в этом формате для TCP-сокетов Windows:

 GET /romeo.txt HTTP/1.1rnHost: data.pr4e.orgrnrn
  

где /romeo.txt это путь от URL-адреса хоста и data.pr4e.org является хозяином

Благодарности кому-то 🙂

Ответ №3:

Я собираюсь предположить, что если вы введете это же имя хоста в веб-браузер, вы получите обратно действительный контент, а не 503.

Три случайных предположения:

1) Вам нужен заголовок User-Agent. Создайте строку запроса как:

  const string request = "GET "   path   " HTTP/1.1n"
 request  = "Host: "   host   "n";
 request  = "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36n";
 request  = "n";
  

2) И, как я уже упоминал в своих комментариях, убедитесь send , что вы отправляете все данные:

 size_t sent = 0;
size_t remaining = request.size();
while (remaining > 0)
{
    const char* data = request.c_str()   sent;
    result = send(sock, data, remaining, 0);
    if (result == SOCKET_ERROR)
            throw SocketError(L"Send", WSAGetLastError());
    sent  = resu<
    remaining -= resu<
}
  

3) Единственной другой вещью может быть shutdown вызов.

Просто удалите следующую строку. Теоретически это не должно иметь значения. Но попробовать стоит.

 result = shutdown(sock, SD_SEND);