2016-06-23 5 views
1

私はウェブサイトから画像をダウンロードしようとしています。問題は、HTTP応答本体からすべてのコンテンツを取得しても、ファイルが開かないということです。私はこれを解決しようとしてきましたが、本当の問題を見つけることはできません。私が気付いたことの一つは、chromiumを使ってダウンロードした画像は、コマンドを使ってコードからダウンロードした画像とは異なる文字を表示することです。 $ cat picture.png |ここではあまり

C++ HTTP応答から画像を取得

#include <netdb.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <unistd.h> 
#include <fstream> 
#include <iostream> 

using std::cout; 
using std::endl; 

//with this function I remove HTTP header info, so I only get content. 
char *removeHTTPHeader(char *buffer) { 
    char *t = strstr(buffer, "\r\n\r\n"); 
    t = t + 4; 
    return t; 
} 

void getPicture(const int &socketfd, const int &bSize) { 
    std::ofstream file("picture.png", 
      std::ofstream::binary | std::ofstream::out); 

    char buffer[bSize]; 
    ssize_t bReceived; 

    bReceived = recv(socketfd, buffer, bSize, 0); 
    char *t = removeHTTPHeader(buffer); 
    file.write(t, strlen(t)); 
    memset(buffer, 0, bSize); 

    while ((bReceived = recv(socketfd, buffer, bSize, 0)) > 0) { 
     file.write(buffer, bReceived); 
     memset(buffer, 0, bSize); 
    } 

    file.close(); 
} 

int main() { 

    int status; 
    addrinfo host_info; 
    addrinfo *host_info_list; 

    memset(&host_info, 0, sizeof(host_info)); 

    host_info.ai_family = AF_UNSPEC; 
    host_info.ai_socktype = SOCK_STREAM; 
    host_info.ai_protocol = 0; 

    status = getaddrinfo("www.pngimg.com", "80", &host_info, &host_info_list); 
    if (status != 0) { 
     cout << "getaddrinfo error" << endl; 
    } 

    int socketfd; 
    socketfd = socket(host_info_list->ai_family, host_info_list->ai_socktype, 
      host_info_list->ai_protocol); 

    addrinfo *rp; 
    for (rp = host_info_list; rp != NULL; rp = rp->ai_next) { 

     socketfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 

     if (socketfd == -1) { 
      cout << "socket error" << endl; 
     } 

     if (connect(socketfd, rp->ai_addr, rp->ai_addrlen) != -1) { 
      break; 
     } 
     close(socketfd); 
    } 

    if (rp == NULL) { 
     cout << "Could not connect!" << endl; 
     exit(EXIT_FAILURE); 
    } 

    freeaddrinfo(host_info_list); 

    const char *msg = 
      "GET /upload/water_PNG3290.png HTTP/1.1\r\nhost: www.pngimg.com\r\nConnection: close\r\n\r\n"; 

    status = send(socketfd, msg, strlen(msg), 0); 

    if (status == -1) { 
     cout << "error sending" << endl; 
     exit(EXIT_FAILURE); 
    } 

    getPicture(socketfd, 1024); 
    close(socketfd); 

    return 0; 
} 

catコマンドを使用してからの画像です: terminal above is picture from my code, below is picture from chromium "save as"

+0

バイナリデータに 'strlen'を使用することはできません。 –

+0

ありがとう、私はそれを変更しました。しかし、それは本当の問題ではないと思います。 – Jake

+1

'char *'から 'std :: string'を構築すると、データの最初の0にも停止します。ヘッダーのバイト数を 'bReceived'から差し引いて残りのバッファーをファイルに書き込むことをお勧めします。 –

答えて

1

問題は、私はCスタイルの文字列にバイナリデータにstrlenを行うことができないことを知らなかったということでした。だからこそ私は関数removeHTTPHeaderにカウンタを追加しなければならなかった。以下は私が変更した関数getPictureとremoveHTTPHeaderです。

char *removeHTTPHeader(char *buffer, int &bodySize) { 
    char *t = strstr(buffer, "\r\n\r\n"); 
    t = t + 4; 

    for (auto it = buffer; it != t; ++it) { 
     ++bodySize; 
    } 

    return t; 
} 

void getPicture(const int &socketfd, const int &bSize) { 
    std::ofstream file("picture.png", 
      std::ofstream::binary | std::ofstream::out); 

    char buffer[bSize]; 
    ssize_t bReceived; 

    bReceived = recv(socketfd, buffer, bSize, 0); 
    int bodySize = 0; 

    char *t = removeHTTPHeader(buffer, bodySize); 
    bodySize = bReceived - bodySize; 

    file.write(t, bodySize); 
    memset(buffer, 0, bSize); 

    while ((bReceived = recv(socketfd, buffer, bSize, 0)) > 0) { 
     file.write(buffer, bReceived); 
     memset(buffer, 0, bSize); 
    } 

    file.close(); 
} 
関連する問題