【问题标题】:My Windows Socket Program Cannot Open Some Urls That Browsers Such As FireFox, IE etc Can我的 Windows Socket 程序无法打开一些 Firefox、IE 等浏览器可以打开的 Url
【发布时间】:2011-12-25 12:16:15
【问题描述】:

我做了以下win32 socket程序来浏览网页。我正在使用wingw 来避免对任何运行时的依赖。要获取 ipaddresses,我通过命令提示符 ping 诸如 www.google.com、www.yahoo.com 之类的 url,并在我的程序中使用这些 ip 地址。端口当然是 80。

我可以通过使用“GET /\r\n”来获取 google、yahoo 等的默认页面。我还可以使用“GET /newsite/index.aspx”获取非默认页面,甚至是目录内的页面,例如http://yasini.com/newsite/index.aspx。程序的输出是从 webserver 接收到的 html 格式,保存在硬盘上。该文件稍后在 Firefox 中打开,以查看通信进展如何。

我做了一个测试网页,http://a.domaindlx.com/trysite/hello.asp,我可以在 Firefox 中打开。然后我 ping 域 a.domaindlx.com 并获取这个 IP 地址 66.36.238.30。我尝试使用“GET /trysite/hello.asp”访问上述页面,但得到的回应是,“此地址未配置网站。此地址未配置网站。”

我知道上述响应是由网络服务器发送的,所以我能够连接到网络服务器。问题是网络服务器无法识别我尝试访问的 url。我用过不同的网页,htm 和 asp 都不能访问。

当尝试直接在浏览器中使用 ipaddress 打开网站时,我得到同样的错误,“没有配置网站...”。

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

#包括windows.h #include stdio.h WSADATA ws; 诠释d; 字符 aa[1000]; 结构 sockaddr_in a; 套接字; 诠释李; 无效 abc(char *p) { 文件 *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 = 套接字(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"); 发送(s,aa,sizeof(aa),0); 李 = 1; 而(李!= 0) { li = recv(s, aa, 1000, 0); abc(aa); } }

注意:请将包含行中的头文件名括在尖括号中,以使代码正常工作。我必须删除它以属性格式化 html。

【问题讨论】:

  • 为什么不省去很多麻烦并使用出色的 libcurl 库呢?便携、坚固且免费。

标签: winapi api sockets


【解决方案1】:

您没有正确遵守协议。你想要GET /trysite/hello.asp HTTP/1.0\r\n\r\n 查看here 了解完整规格。

【讨论】:

  • 我已经尝试过了,从网络服务器收到以下消息:HTTP/1.0 404 Not Found Server: Microsoft-IIS/5.0 Date: Wed, 09 Nov 2011 19:42:59 GMT Content-Type: text/html Content-Length: 111 X-Cache: MISS from linto Connection: close 此地址未配置网站。内容长度:111 X 缓存:来自 linto 的 MISS 连接:关闭 此地址未配置网站。内容长度:111 X-缓存:来自 linto 的 MISS 连接:关闭
  • 好的,我搞定了,正确的格式是:“GET a.domaindlx.com/trysite/my.htm HTTP/1.0\r\n\r\n”。这意味着完整的 url,包括协议名和域名。在工作代码中,我必须删除 strcat 行并将 strcpy 行替换为: strcpy(aa, "GET a.domaindlx.com/trysite/my.htm HTTP/1.0\r\n\r\n");其余的代码都很好。感谢卢克为我指明了正确的方向。
  • 我相信语法通常是供代理使用的,尽管它可能适用于所有类型的客户端。大多数客户端会在请求中添加 Host: 标头;例如GET /trysite/my.htm HTTP/1.0\r\nHost: a.domaindlx.com\r\n\r\n
【解决方案2】:

麻烦的 URL 在子域上运行。成功的 URL 不是。许多网络服务器在同一个物理 IP 上托管多个帐户,因此他们需要知道正在请求哪个特定域/子域才能访问正确的帐户。您需要在请求中包含 Host 标头。

还请注意,当您调用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。然后你可以确切地看到网络浏览器(或任何其他套接字应用程序)实际发送和接收的内容。然后你可以根据需要在你的代码中匹配它。

【讨论】:

    【解决方案3】:

    您的代码有两个问题。第一个是在HTTP 1.0之前应该有一个空格而不是\r\n。如果没有这个,您将发送 HTTP 0.9。

    第二个问题是一些IP地址被用来承载多个站点,需要发送一个Host头。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-25
      • 2017-08-01
      • 1970-01-01
      • 2012-04-21
      • 1970-01-01
      • 1970-01-01
      • 2022-12-06
      • 2021-07-28
      相关资源
      最近更新 更多