如何使用C从http下载文件?

费伯

我花了最后几天试图弄清楚如何从URL下载文件。这是我对套接字的第一个挑战,我正在使用它来了解协议,因此我想在不使用cURL库且仅使用C语言的情况下进行操作!我搜索了很多...。现在我可以打印页面的源代码,但是我认为它与文件不同,我不必只将接收到的数据从缓冲区放到文件中,对吗?有小费吗?

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

int main(void)
{
    char domain[] = "www.sstatic.net", path[]="stackexchange/img/logos/so/so-logo-med.png"; //example 
    int sock, bytes_received;  
    char send_data[1024],recv_data[9999], *p;
    struct sockaddr_in server_addr;
    struct hostent *he;
    FILE *fp;

    he = gethostbyname(domain);
    if (he == NULL){
       herror("gethostbyname");
       exit(1);
    }

    if ((sock = socket(AF_INET, SOCK_STREAM, 0))== -1){
       perror("Socket");
       exit(1);
    }
    server_addr.sin_family = AF_INET;     
    server_addr.sin_port = htons(80);
    server_addr.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(server_addr.sin_zero),8); 
    if (connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){
       perror("Connect");
       exit(1); 
    }

    snprintf(send_data, sizeof(send_data), "GET /%s HTTP/1.1\r\nHost: /%s\r\n\r\n", path, domain);
    //printf("%s\n", send_data);
    send(sock, send_data, strlen(send_data), 0); 
    printf("Data sended.\n");  

    fp=fopen("received_file","wb");

    bytes_received = recv(sock, recv_data, 9999, 0);
    recv_data[bytes_received] = '\0';
    printf("Data receieved.\n");
    printf("%s\n", recv_data);

    p = strstr(recv_data, "\r\n\r\n");  //to find "\r\n\r\n" sequence and put the pointer p after that
    p=p+4;

    fwrite(p,strlen(p),1,fp);       

    close(sock);
    fclose(fp);

return 0;
} 

更新1感谢milevyo的一些改进!它可以与txt文件配合使用,但不能与其他类型的文件(在这种情况下为png)配合使用

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

int main(void){

    //char domain[] = "www.gnu.org", path[]="/licenses/gpl.txt"; //example 
    char domain[] = "sstatic.net", path[]="stackexchange/img/logos/so/so-logo-med.png"; //example 
        int sock, bytes_received;  
    char send_data[1024],recv_data[9999];
    struct sockaddr_in server_addr;
    struct hostent *he;
    FILE *fp;

    he = gethostbyname(domain);
    if (he == NULL){
       herror("gethostbyname");
       exit(1);
    }

    if ((sock = socket(AF_INET, SOCK_STREAM, 0))== -1){
       perror("Socket");
       exit(1);
    }
    server_addr.sin_family = AF_INET;     
    server_addr.sin_port = htons(80);
    server_addr.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(server_addr.sin_zero),8); 

    printf("Connecting ...\n");
    if (connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){
       perror("Connect");
       exit(1); 
    }

    printf("Sending data ...\n");

    snprintf(send_data, sizeof(send_data), "GET /%s HTTP/1.1\r\nHost: /%s\r\n\r\n", path, domain);

    if(send(sock, send_data, strlen(send_data), 0)==-1){
        perror("send");
        exit(2); 
    }
    printf("Data sent.\n");  

    fp=fopen("received_file","wb");
    printf("Recieving data...\n\n");
    while((bytes_received = recv(sock, recv_data, 9999, 0))>0){
        if(bytes_received==-1){
            perror("recieve");
            exit(3);
        }
        recv_data[bytes_received] = '\0';

        fwrite(recv_data,bytes_received,1,fp);
        printf("%s", recv_data);
    }



    close(sock);
    fclose(fp);
    printf("\n\nDone.\n\n");
    return 0;
}

此代码产生一个334字节的文件(而不是原始文件的12,4kb),其中包含以下内容:

HTTP/1.1 400 Bad Request
Date: Sat, 28 Nov 2015 16:20:45 GMT
Content-Type: text/html
Content-Length: 177
Connection: close
Server: -nginx
CF-RAY: -

<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare-nginx</center>
</body>
</html>

有人知道如何解决这个“ 400 Bad Request”吗?

米列夫约

这是先前发布的代码的更新。只是一个很小的例子,http协议还远未实现。

重新格式化代码或对其进行修改是非常值得欢迎的。

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

#include <string.h>


int ReadHttpStatus(int sock){
    char c;
    char buff[1024]="",*ptr=buff+1;
    int bytes_received, status;
    printf("Begin Response ..\n");
    while(bytes_received = recv(sock, ptr, 1, 0)){
        if(bytes_received==-1){
            perror("ReadHttpStatus");
            exit(1);
        }

        if((ptr[-1]=='\r')  && (*ptr=='\n' )) break;
        ptr++;
    }
    *ptr=0;
    ptr=buff+1;

    sscanf(ptr,"%*s %d ", &status);

    printf("%s\n",ptr);
    printf("status=%d\n",status);
    printf("End Response ..\n");
    return (bytes_received>0)?status:0;

}

//the only filed that it parsed is 'Content-Length' 
int ParseHeader(int sock){
    char c;
    char buff[1024]="",*ptr=buff+4;
    int bytes_received, status;
    printf("Begin HEADER ..\n");
    while(bytes_received = recv(sock, ptr, 1, 0)){
        if(bytes_received==-1){
            perror("Parse Header");
            exit(1);
        }

        if(
            (ptr[-3]=='\r')  && (ptr[-2]=='\n' ) &&
            (ptr[-1]=='\r')  && (*ptr=='\n' )
        ) break;
        ptr++;
    }

    *ptr=0;
    ptr=buff+4;
    //printf("%s",ptr);

    if(bytes_received){
        ptr=strstr(ptr,"Content-Length:");
        if(ptr){
            sscanf(ptr,"%*s %d",&bytes_received);

        }else
            bytes_received=-1; //unknown size

       printf("Content-Length: %d\n",bytes_received);
    }
    printf("End HEADER ..\n");
    return  bytes_received ;

}

int main(void){

    char domain[] = "sstatic.net", path[]="stackexchange/img/logos/so/so-logo-med.png"; 

    int sock, bytes_received;  
    char send_data[1024],recv_data[1024], *p;
    struct sockaddr_in server_addr;
    struct hostent *he;


    he = gethostbyname(domain);
    if (he == NULL){
       herror("gethostbyname");
       exit(1);
    }

    if ((sock = socket(AF_INET, SOCK_STREAM, 0))== -1){
       perror("Socket");
       exit(1);
    }
    server_addr.sin_family = AF_INET;     
    server_addr.sin_port = htons(80);
    server_addr.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(server_addr.sin_zero),8); 

    printf("Connecting ...\n");
    if (connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){
       perror("Connect");
       exit(1); 
    }

    printf("Sending data ...\n");

    snprintf(send_data, sizeof(send_data), "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", path, domain);

    if(send(sock, send_data, strlen(send_data), 0)==-1){
        perror("send");
        exit(2); 
    }
    printf("Data sent.\n");  

    //fp=fopen("received_file","wb");
    printf("Recieving data...\n\n");

    int contentlengh;

    if(ReadHttpStatus(sock) && (contentlengh=ParseHeader(sock))){

        int bytes=0;
        FILE* fd=fopen("test.png","wb");
        printf("Saving data...\n\n");

        while(bytes_received = recv(sock, recv_data, 1024, 0)){
            if(bytes_received==-1){
                perror("recieve");
                exit(3);
            }


            fwrite(recv_data,1,bytes_received,fd);
            bytes+=bytes_received;
            printf("Bytes recieved: %d from %d\n",bytes,contentlengh);
            if(bytes==contentlengh)
            break;
        }
        fclose(fd);
    }



    close(sock);
    printf("\n\nDone.\n\n");
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何使用Vala通过HTTP下载文件?

来自分类Dev

如何使用node.js和http下载文件?

来自分类Dev

如何使用http post Node.js下载文件

来自分类Dev

如何从http url下载文件?

来自分类Dev

如何通过HTTP下载文件?

来自分类Dev

如何使用C Socket编程下载文件

来自分类Dev

如何使用c#名称下载文件?

来自分类Dev

如何使用C#从NetSuite中的FileCabinet下载文件

来自分类Dev

C#如何使用libcurlnet下载文件

来自分类Dev

如何使用Python 2.7通过HTTP使用多线程下载文件(异步下载)

来自分类Dev

如何使用restsharp下载文件

来自分类Dev

如何使用硒下载文件?

来自分类Dev

如何使用锚标记<a>下载文件

来自分类Dev

如何使用jQuery下载文件?

来自分类Dev

如何使用Cowboy下载文件?

来自分类Dev

如何使用Java Spark下载文件?

来自分类Dev

如何使用php下载文件?

来自分类Dev

如何使用jxbrowser库下载文件?

来自分类Dev

如何使用Express从url下载文件?

来自分类Dev

如何使用git从heroku下载文件

来自分类Dev

如何使用JavaScript强制下载文件?

来自分类Dev

如何使用Cowboy下载文件?

来自分类Dev

如何使用php下载文件?

来自分类Dev

如何使用angularjs下载文件?

来自分类Dev

如何使用VBA从Sharepoint下载文件

来自分类Dev

使用curl下载文件的C程序

来自分类Dev

使用c#WebClient下载文件

来自分类Dev

如何下载文件

来自分类Dev

如何下载文件?