【问题标题】:Making an HTTP Request with Sockets through a proxy通过代理使用套接字发出 HTTP 请求
【发布时间】:2015-12-17 16:26:02
【问题描述】:

我想使用套接字发出 HTTP 请求。到目前为止,这是我的代码:

   #include "stdafx.h"
#ifndef UNICODE
#define UNICODE
#endif

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

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

#pragma comment(lib, "ws2_32.lib")
using namespace std;

int main()
{
    try {
        WSADATA wsaData;
        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        sockaddr_in clientService;


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

        memset(&clientService, 0, sizeof(clientService));
        clientService.sin_addr.s_addr = inet_addr("83.233.53.59"); // Proxy IP
        clientService.sin_family = AF_INET;
        clientService.sin_port = htons(10200);

        if (bind(Socket, (struct sockaddr *) &clientService, sizeof(clientService)) < 0) {
            perror("bind");
            exit(1);
        }
        system("pause");
        return 0;
        struct hostent *host;
        host = gethostbyname("www.google.com");
        SOCKADDR_IN SockAddr;
        SockAddr.sin_port = htons(80);
        SockAddr.sin_family = AF_INET;
        // SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
        memcpy(host->h_addr, &(SockAddr.sin_addr.s_addr), host->h_length);
        std::cout << "Connecting...\n";

        iResult = connect(Socket, (SOCKADDR *)& clientService, sizeof(clientService));
        if (iResult != 0) {
            std::cout << "Could not connect";
            getchar();
            return 1;
        }
        std::cout << "Connected.\n";
        send(Socket, "GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"), 0);
        char buffer[10000];
        int nDataLength;
        while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
            int i = 0;
            while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
                std::cout << buffer[i];
                i += 1;
            }
        }
        iResult = closesocket(Socket);
        WSACleanup();

        system("pause");
    }
    catch (...) {
        system("pause");

    }
    return 0;
}

但它不起作用,没有程序自行关闭而不给我留下网页的 HTML 源代码。怎么了?

我该如何解决?

【问题讨论】:

  • 您尝试此操作时发生了什么?它给你错误了吗?挂了吗?它崩溃了吗?
  • @erip 一切正常。但我不知道如何通过代理连接到确定的主机,这就是我要问的。
  • 对于 http 请求,您只需 connect 代理地址和端口并发送 GET http://www.google.com/ HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n
  • @frymode 这就是我不明白的。你能给我举个例子吗?
  • google 代理请求是如何完成的,而不是把你的代码放在这里寻求帮助有多难。参见例如forensicswiki.org/wiki/Proxy_server#HTTP_proxies

标签: c++ sockets


【解决方案1】:

这适用于我的机器,但我不在 Windows 机器上。我在freeBSD(OS X)机器上。在解决 gethostbyname 时遇到问题,不确定这是怎么回事,但这有效并连接并从 google 下载了代码。

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN

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

#pragma comment(lib, "ws2_32.lib")
using namespace std;

int main()
{
    try {
        //        WSADATA wsaData;
        //        int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        // sockaddr_in clientService;


        int Socket = socket(AF_INET, SOCK_STREAM, 0);
        /*
         memset(&clientService, 0, sizeof(clientService));
         clientService.sin_addr.s_addr = inet_addr("83.233.53.59"); // Proxy IP
         clientService.sin_family = AF_INET;
         clientService.sin_port = htons(10200);

         if (bind(Socket, (struct sockaddr *) &clientService, sizeof clientService) == -1) {
         perror("bind");
         exit(1);
         }
         system("pause");
         return 0;
         */
         const char hostname[] ="www.google.com";
         struct hostent * host;
//         host = gethostbyname(hostname);

        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("83.233.53.59");
        //        memcpy(host->h_addr, &(SockAddr.sin_addr.s_addr), host->h_length);
        std::cout << "Connecting...\n";

        int iResult = connect(Socket, (struct sockaddr *)& SockAddr, sizeof(SockAddr));
        if (iResult != 0) {
            std::cout << "Could not connect";
            getchar();
            return 1;
        }
        std::cout << "Connected.\n";
        send(Socket, "GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP / 1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"), 0);
        char buffer[10000];
        int nDataLength;
        while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
            int i = 0;
            while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
                std::cout << buffer[i];
                i += 1;
            }
        }
        iResult = close(Socket);
        //        WSACleanup();

        system("pause");
    }
    catch (...) {
        system("pause");

    }
    return 0;
}

http: 级别的身份验证失败,但输出如下:

Connecting...
Connected.
HTTP/1.0 401 Unauthorized
Server: uhttpd/1.0.0
Date: Thu, 17 Dec 2015 18:29:04 GMT
WWW-Authenticate: Basic realm="                 "
Content-Type: text/html; charset="UTF-8"
Connection: close

<HTML><HEAD><META http-equiv='Pragma' content='no-cache'><META http-equiv='Cache-Control' content='no-cache'><TITLE> 401 Authorization</TITLE>
<script language=javascript type=text/javascript>
function cancelevent()
{
sh: pause: command not found
Program ended with exit code: 0

【讨论】:

  • 很好,但我怎样才能在 Windows 上制作呢?
  • Berkeley 套接字在所有系统上几乎相同。我已经在 Windows 上完成了它们,除了包含文件之外几乎没有任何变化。也就是说,将包含文件更改回您拥有的文件,它应该可以工作。
  • 如果您仍然想通过代理,那么您需要将“GET / ...”字符串更改为“CONNECT ...”字符串,请参阅此处的答案:stackoverflow.com/questions/9191860/…
【解决方案2】:

可能会出错的一件事是,您的应用程序在以下循环期间访问越界数组索引时可能会崩溃:

while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
    ...
    i += 1;
}

您当前的代码不能保证buffer 包含一个会使您的循环终止的字节,因此它可能会无限期地继续。您必须通过在访问数组索引之前进行额外检查来防止这种情况。考虑到nDataLength 总是小于或等于sizeof(buffer),试试这个:

while (i < nDataLength &&
    (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'))
{
    // Do your printing.
    i++;
}

或者更简单:

while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
{
    // Do your printing.
    i++;

    if (i >= nDataLength)
        break; // Exit the loop.
}

【讨论】:

  • 感谢您的帮助。
【解决方案3】:
system("pause");
return 0;

此代码阻止执行任何后续操作。删除。

您的代码还有许多其他问题。例如,您将套接字绑定到代理地址。那没有意义。消除。即将连接socket,完全不需要绑定。

然后您向代理发送了一个无效的 GET 请求。在这种情况下,GET 请求应该包含完整的 URL,而不仅仅是相对 URL。

当您搜索空间等时,您超出了接收缓冲区。您需要通过 recv() 返回的计数来绑定该搜索。

等等。

【讨论】:

  • Ofc 我打算删除它。 system() 功能不好。我可以删除return 0using namespace std;。我只是将其用于测试目的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-13
  • 2023-04-06
相关资源
最近更新 更多