簡體   English   中英

C ++從http下載二進制文件

[英]C++ download binary file from http

我正在為我用c ++編寫的第一個程序創建一個更新機制。 理論是:

  1. 程序將其版本作為http標頭發送到服務器php
  2. 服務器檢查是否存在更高版本
  3. 如果是,則服務器將新二進制文件發送到客戶端。

大多數都有效,但收到的二進制文件格式不正確。 當我將格式錯誤的exe與工作exe進行比較時,我在已編譯的exe中的\\r\\n s的地方有差異。 似乎\\r加倍了。

我下載的c ++代碼:

void checkForUpdates () {
    SOCKET sock = createHttpSocket (); // creates the socket, nothing wrong here, other requests work

    char* msg = (char*)"GET /u/2 HTTP/1.1\r\nHost: imgup.hu\r\nUser-Agent: imgup uploader app\r\nVersion: 1\r\n\r\n";

    if (send(sock, msg, strlen(msg), 0) == SOCKET_ERROR) {
        error("send failed with error\n");
    }
    shutdown(sock, SD_SEND);

    FILE *fp = fopen("update.exe", "w");
    char answ[1024] = {};
    int iResult;
    bool first = false;
    do {
        if ((iResult = recv(sock, answ, 1024, 0)) < 0) {
            error("recv failed with error\n");
        }
        if (first) {
            info (answ); // debug purposes
            first = false;
        } else {
            fwrite(answ, 1, iResult, fp);
            fflush(fp);
        }
    } while (iResult > 0);
    shutdown(sock, SD_RECEIVE);

    if (closesocket(sock) == SOCKET_ERROR) {
        error("closesocket failed with error\n");
    }

    fclose(fp);

    delete[] answ;
}

和我的PHP來處理請求

<?php
if (!function_exists('getallheaders')) {
    function getallheaders() {
        $headers = '';
        foreach ($_SERVER as $name => $value) {
            if (substr($name, 0, 5) == 'HTTP_') {
                $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
            }
        }
        return $headers;
    }
}

$version = '0';
foreach (getallheaders() as $name => $value) {
    if (strtolower ($name) == 'version') {
        $version = $value;
        break;
    }
}

if ($version == '0') {
    exit('error');
}


if ($handle = opendir('.')) {
    while (false !== ($entry = readdir($handle))) {
        if ($entry != '.' && $entry != '..' && $entry != 'u.php') {
            if (intval ($entry) > intval($version)) {
                header('Content-Version: ' . $entry);
                header('Content-Length: ' . filesize($entry));
                header('Content-Type: application/octet-stream');
                echo "\r\n";
                ob_clean();
                flush();
                readfile($entry);
                exit();
            }
        }
    }
    closedir($handle);
}
echo 'error2';


?>

注意我發送頭文件后刷新內容的方式ob_clean(); flush(); ob_clean(); flush(); 所以我不必用c ++解析它們。 寫入文件的第一個字節很好,所以我懷疑這里有什么問題。

另外,二進制文件的示例比較http://i.imgup.hu/meC16C.png

問題:http是否在二進制文件傳輸中轉義\\r\\n 如果不是,導致此行為的原因是什么?如何解決此問題?

fopen以您指定的模式打開文件,首先讀/寫/兩者,然后追加,然后是二進制標識符。

r / w應該對你清楚,追加也很明顯。 你的案例中的詭計和麻煩是二元模式。

如果文件被作為文本文件(沒有“b”)進行威脅,則根據應用程序運行的環境,在文本模式下的輸入/輸出操作中可能會發生一些特殊字符轉換,以使它們適應特定於系統的文本文件格式。 在Windows上,這將是\\ r \\ n,在Linux機器上你有\\ n並且在某些架構上存在,它是\\ r \\ n。

在您的情況下,輸入文件將作為文本文件讀取。 這意味着,從HTTP數據中讀取文件時,所有行結尾都會被轉換。

將文件作為二進制文件打開(確實是這樣!)避免了文件不再具有二進制文件的麻煩。

問題是輸出文件沒有以二進制模式打開。 要做到這一點,將模式更改為“wb”而不是“w”,如下所示:

FILE *fp = fopen("update.exe", "wb");

在Windows上的文本模式下,ctrl + z字符指定搜索/讀取時文件的結尾,並且在寫入時將換行符\\ n轉換為\\ r \\ n,並且在讀取時將\\ r \\ n對轉換為\\ n。 在二進制模式下,不以任何方式解釋或翻譯文件數據。

在其他平台上,翻譯可能不適用,但通過指定顯式模式來顯示代碼的意圖仍然是一種好的做法,即使在非必要時也是如此。 對於可移植的代碼尤其如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM