HTML – 下载HTTP通过套接字(C)

最近我开始用 this guide开始从互联网上下载文件.我读了它并想出了下面的代码来下载一个网站的HTTP主体.唯一的问题是,它不起作用.调用recv()调用代码停止.它不会崩溃,它只是继续运行.这是我的错吗?我使用错误的approch吗?我打算使用代码不仅下载.html文件内容,还要下载其他文件(zip,png,jpg,dmg …).我希望有人可以帮助我.这是我的代码
#include <stdio.h>
#include <sys/socket.h> /* SOCKET */
#include <netdb.h> /* struct addrinfo */
#include <stdlib.h> /* exit() */
#include <string.h> /* memset() */
#include <errno.h> /* errno */
#include <unistd.h> /* close() */
#include <arpa/inet.h> /* IP Conversion */

#include <stdarg.h> /* va_list */

#define SERVERNAME "developerief2.site11.com"
#define PROTOCOL "80"
#define MAXDATASIZE 1024*1024

void errorOut(int status,const char *format,...);
void *get_in_addr(struct sockaddr *sa);

int main (int argc,const char * argv[]) {
    int status;

    // GET ADDRESS INFO
    struct addrinfo *infos; 
    struct addrinfo hints;

    // fill hints
    memset(&hints,sizeof(hints));
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_UNSPEC;

    // get address info
    status = getaddrinfo(SERVERNAME,PROTOCOL,&hints,&infos);
    if(status != 0)
        errorOut(-1,"Couldn't get addres information: %s\n",gai_strerror(status));

    // MAKE SOCKET
    int sockfd;

    // loop,use first valid
    struct addrinfo *p;
    for(p = infos; p != NULL; p = p->ai_next) {
        // CREATE SOCKET
        sockfd = socket(p->ai_family,p->ai_socktype,p->ai_protocol);
        if(sockfd == -1)
            continue;

        // TRY TO CONNECT
        status = connect(sockfd,p->ai_addr,p->ai_addrlen);
        if(status == -1) {
            close(sockfd);
            continue;
        }

        break;
    }

    if(p == NULL) {
        fprintf(stderr,"Failed to connect\n");
        return 1;
    }

    // LET USER KNow
    char printableIP[INET6_ADDRSTRLEN];
    inet_ntop(p->ai_family,get_in_addr((struct sockaddr *)p->ai_addr),printableIP,sizeof(printableIP));
    printf("Connection to %s\n",printableIP);

    // GET RID OF INFOS
    freeaddrinfo(infos);

    // RECEIVE DATA
    ssize_t receivedBytes;
    char buf[MAXDATASIZE];
    printf("Start receiving\n");
    receivedBytes = recv(sockfd,buf,MAXDATASIZE-1,0);
    printf("Received %d bytes\n",(int)receivedBytes);
    if(receivedBytes == -1)
        errorOut(1,"Error while receiving\n");

    // null terminate
    buf[receivedBytes] = '\0';

    // PRINT
    printf("Received Data:\n\n%s\n",buf);

    // CLOSE
    close(sockfd);

    return 0;
}

void *get_in_addr(struct sockaddr *sa) {
    // IP4
    if(sa->sa_family == AF_INET)
        return &(((struct sockaddr_in *) sa)->sin_addr);

    return &(((struct sockaddr_in6 *) sa)->sin6_addr);
}

void errorOut(int status,...) {
    va_list args;
    va_start(args,format);
    vfprintf(stderr,format,args);
    va_end(args);
    exit(status);
}

解决方法

如果你想使用HTTP获取文件,那么 libcURL可能是你在C中最好的选择.但是,如果你使用它作为一种学习网络编程的方法,那么你将不得不学习更多关于HTTP的知识.检索文件.

您在当前程序中看到的是,您需要先发送文件的明确请求,然后才能检索它.我将从阅读RFC2616开始.不要试图理解这一切 – 这个例子需要阅读很多.阅读first section以了解HTTP的工作原理,然后阅读第4,5,and 6节以了解基本的消息格式.

以下是stackoverflow Questions页面的HTTP请求的示例:

GET https://stackoverflow.com/questions HTTP/1.1\r\n
Host: stackoverflow.com:80\r\n
Connection: close\r\n
Accept-Encoding: identity,*;q=0\r\n
\r\n

我认为这是一个最小的要求.我明确添加了CRLF,以显示空行用于终止请求标头块as described in RFC2616.如果省略Accept-Encoding标头,则结果文档可能会被转换为gzip压缩流,因为HTTP明确允许这样做,除非你告诉服务器你不想要它.

服务器响应还包含描述响应的元数据的HTTP标头.以下是上一个请求的响应示例:

HTTP/1.1 200 OK\r\n
Server: Nginx\r\n
Date: Sun,01 Aug 2010 13:54:56 GMT\r\n
Content-Type: text/html; charset=utf-8\r\n
Connection: close\r\n
Cache-Control: private\r\n
Content-Length: 49731\r\n
\r\n
\r\n
\r\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ... 49,667 bytes follow

如果您想使用HTTP获取文件,这个简单的示例应该让您了解要实现的内容.这是最好的情况,最简单的例子.这不是我会轻易承担的事情,但它可能是学习和欣赏HTTP的最佳方式.

如果您正在寻找一种学习网络编程的简单方法,这是一个很好的开始方式.我建议拿起TCP/IP Illustrated,Volume 1UNIX Network Programming,Volume 1的副本.这些可能是真正学习如何编写基于网络的应用程序的最佳方法.我可能从编写FTP client开始,因为FTP一个更简单的协议开始.

如果您尝试了解与HTTP相关的详细信息,那么:

>购买HTTP: the Definitive Guide并阅读
>阅读RFC2616直到您理解为止

>尝试使用telnet服务器80并手动输入请求的示例
>下载cURL客户端并使用–verbose和–include命令行选项,以便您可以看到发生了什么

>阅读Fielding’s dissertation,直到HTTP真的有意义.

只是不打算为企业使用编写自己的HTTP客户端.你不想这样做,相信我是一个一直在维持这样一个错误的人…

相关文章

vue阻止冒泡事件 阻止点击事件的执行 &lt;div @click=&a...
尝试过使用网友说的API接口获取 找到的都是失效了 暂时就使用...
后台我拿的数据是这样的格式: [ {id:1 , parentId: 0, name:...
JAVA下载文件防重复点击,防止多次下载请求,Cookie方式快速简...
Mip是什么意思以及作用有哪些