我的socket程序无法打开FireFox、IE等浏览器可以打开的一些URL

问题描述 投票:0回答:3

我制作了以下Win32套接字程序来浏览网页。我使用 Mingw 来避免对任何运行时的依赖。

要获取 IP 地址,我通过命令提示符 ping 诸如

www.google.com
www.yahoo.com
之类的 url,然后在我的程序中使用这些 IP 地址。端口当然是80。

我可以使用

"GET /\r\n"
获取 Google、Yahoo 等的默认页面。我还可以获取非默认页面,甚至是目录内的页面,例如使用
http://yasini.com/newsite/index.aspx
来获取
"GET /newsite/index.aspx"

程序的输出以从网络服务器接收的 HTML 形式保存在硬盘上。稍后在 FireFox 中打开该文件以查看通信情况。

我做了一个测试网页,

http://a.domaindlx.com/trysite/hello.asp
,我可以在FireFox中打开它。然后我 ping 域
a.domaindlx.com
并获得 IP 地址
66.36.238.30
。然后我尝试使用
"GET /trysite/hello.asp"
访问上述页面,但我得到了这样的响应:

此地址未配置任何网站。

我知道这个响应是由网络服务器发送的,所以我能够连接到网络服务器。问题是网络服务器无法识别我尝试访问的 URL。我使用过不同的网页,HTML 和 ASP,但都无法访问。

当尝试直接在浏览器中使用其 IP 地址打开网站时,我收到相同的

"No website is configured..."
错误。

基本的难题是,为什么这些页面可以通过 FireFox 等浏览器访问,但不能通过我的代码访问?我的代码本质上是一个浏览器,这意味着它在端口 80 处打开与网络服务器的连接。

#include <windows.h>
#include <stdio.h>

WSADATA ws;

int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
int li;

void abc(char *p)
{
    FILE *fp = fopen("c:\\data.htm", "a+");
    fprintf(fp, "%s\n", p);
    fclose(fp);
}

_stdcall WinMain (HINSTANCE i, HINSTANCE j, char * k, int l)
{
    d = WSAStartup(0x101, &ws);
    sprintf(aa, "WSASTARTUP = %d", d);
    abc(aa);

    s = socket(AF_INET, SOCK_STREAM, 0);
    sprintf(aa, "SOCKET = %d", s);
    abc(aa);

    a.sin_family = AF_INET;
    a.sin_port = htons(80);
    //a.sin_addr.s_addr = inet_addr("74.125.236.145");
    a.sin_addr.s_addr = inet_addr("66.36.238.30"); //a.domaindlx.com
    //a.sin_addr.s_addr = inet_addr("206.225.85.18"); //www.domaindlx.com
    //a.sin_addr.s_addr = inet_addr("87.248.122.122"); //www.yahoo.com
    //a.sin_addr.s_addr = inet_addr("72.167.153.9"); //www.yasini.com
    d = connect(s, (struct sockaddr *) &a, sizeof(a));

    strcpy(aa, "GET /trysite/hello.asp\r\n");
    strcat(aa, "HTTP 1.0 \r\n\r\n");
    send(s, aa, sizeof(aa), 0);
    li = 1;

    while(li != 0)
    {
        li = recv(s, aa, 1000, 0);
        abc(aa);
    }
}
sockets winapi
3个回答
2
投票

您的代码有两个问题。

第一个问题是

\r\n
之前应该有一个空格,而不是
HTTP 1.0
。 如果没有这个,您将发送 HTTP 0.9。

第二个问题是某些 IP 地址用于托管多个站点,需要发送

Host
标头。

如果您添加

Host
标头,告诉您“此地址没有配置网站”的网站可能会工作得更好。 您对该网站的请求应如下所示:

"GET /trysite/hello.asp HTTP 1.0\r\nHost: a.domaindlx.com\r\n\r\n"


1
投票

许多网络服务器(尤其是提供共享托管的网络服务器)可以在同一物理 IP 上托管多个帐户,因此它们需要知道正在请求哪个特定网站才能访问正确的帐户。 要指定目标网站,您需要在 HTTP 请求中包含

Host
标头。

Host
标头在 HTTP 1.0(您正在使用的)中是可选的,但实际上在 HTTP 1.1 及以后版本中是必需的,否则请求将失败。

另请注意,当您调用

send()
发送请求时,您正在发送
aa
缓冲区的全部 1000 个字节,这是错误的。 您只需发送您实际填写的内容即可。

最后,一般来说,您并没有真正很好地管理套接字。 您需要更好的错误处理。

试试这个:

#include <windows.h>
#include <stdio.h>

void abc(char *p, int l = -1)
{
    FILE *fp = fopen("c:\\data.htm", "a+");
    if (fp)
    {
        if (l == -1) l = strlen(p);
        fwrite(p, 1, l, fp);
        fclose(fp);
    }
}

int WINAPI WinMain (HINSTANCE i, HINSTANCE j, char * k, int l)
{
    char aa[1000];

    WSADATA ws;
    int d = WSAStartup(0x101, &ws);
    sprintf(aa, "WSASTARTUP = %d\n", d);
    abc(aa);

    if (d == 0)
    {
        SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
        sprintf(aa, "SOCKET = %d\n", s);
        abc(aa);

        if (s != INVALID_SOCKET)
        {
            char *host = "a.domaindlx.com";
            char *file = "/trysite/hello.asp";

            struct sockaddr_in a;
            memset(&a, 0, sizeof(a));

            a.sin_family = AF_INET;
            a.sin_port = htons(80);

            struct hostent *h = gethostbyname(host);
            if (!h)
            {
                sprintf(aa, "gethostbyname(\"%s\") FAILED\n", host);
                abc(aa);
            }
            else
            {
                sprintf(aa, "gethostbyname(\"%s\") TYPE = %d\n", host, h->h_addrtype);
                abc(aa);

                if (h->h_addrtype == AF_INET)
                {
                    a.sin_addr = * (struct in_addr*) h->h_addr;
                    sprintf(aa, "gethostbyname(\"%s\") IP = %s\n", host, inet_ntoa(a.sin_addr));
                    abc(aa);

                    d = connect(s, (struct sockaddr *) &a, sizeof(a));
                    sprintf(aa, "CONNECT = %d\n", d);
                    abc(aa);

                    if (d == 0)
                    {
                        sprintf(aa,
                            "GET %s HTTP/1.0\r\n"
                            "Host: %s\r\n"
                            "Connection: close\r\n"
                            "\r\n",
                            file, host);

                        char *p = aa;
                        int t = strlen(aa);
                        int li;

                        do
                        {
                            li = send(s, p, t, 0);
                            if (li < 1)
                                break;

                            p += li;
                            t -= li;
                        }
                        while (t > 0);

                        if (t != 0)
                        {
                            abc("SEND FAILED\n");
                        }
                        else
                        {
                            abc("SEND OK\n");

                            do
                            {
                                li = recv(s, aa, sizeof(aa), 0);
                                if (li < 1)
                                    break;

                                abc(aa, li);
                            }
                            while (true);
                        }
                    }
                }
            }

            closesocket(s);
        }

        WSACleanup();
    }

    return 0;
}

我强烈建议您使用数据包嗅探器,例如Wireshark。 然后您可以准确地看到网络浏览器(或任何其他套接字应用程序)实际发送和接收的内容。 然后您可以根据需要在代码中进行匹配。


0
投票

您没有正确遵循协议。 您想要

GET /trysite/hello.asp HTTP/1.0\r\n\r\n
请参阅此处了解完整规格。

© www.soinside.com 2019 - 2024. All rights reserved.