C ++从http下载二进制文件

时间:2013-06-02 18:56:14

标签: php c++ http binary

我正在为我用c ++编写的第一个程序创建一个更新机制。 理论是:

  1. 程序将其版本作为http标头发送到服务器php
  2. 服务器检查是否存在更新版本
  3. 如果是,则服务器将新二进制文件发送给客户端。
  4. 但是大部分都有效,但收到的二进制文件格式不正确。当我将格式错误的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();后刷新内容的方式,所以我不必在c ++中解析它们。写入文件的第一个字节很好,所以我怀疑这里有什么问题。

    此外,二进制文件http://i.imgup.hu/meC16C.png

    的示例比较

    问题:http是否在二进制文件传输中转义\r\n?如果不是,导致此行为的原因是什么?如何解决此问题?

2 个答案:

答案 0 :(得分:5)

fopen以您指定的模式打开文件,首先读/写/两者,然后追加,然后是二进制标识符。

你应该清楚r / w,追加也很明显。诡计&amp;您遇到的问题是二进制模式。

如果文件被作为文本文件(没有“b”)进行威胁,则根据应用程序运行的环境,在文本模式下的输入/输出操作中可能会发生一些特殊的字符转换,以使它们适应系统特定的文本文件格式。在Windows上,这将是\ r \ n,在Linux机器上你有\ n并且在某些架构上存在,它是\ r \ n。

在您的情况下,输入文件将作为文本文件读取。这意味着,从HTTP数据中读取文件时,所有行结尾都会被转换。

将文件作为二进制文件打开(实际上是!),避免了文件不再具有二进制文件的麻烦。

答案 1 :(得分:5)

问题是输出文件没有以二进制模式打开。为此,将模式更改为“wb”而不是“w”,如下所示:

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

在Windows上的文本模式下,ctrl + z字符指定搜索/读取时文件的结尾,并且在写入时将换行符\ n转换为\ r \ n,并将\ r \ n对转换为\ n在阅读。在二进制模式下,不会以任何方式解释或翻译文件数据。

在其他平台上,翻译可能不适用,但通过指定显式模式来显示代码的意图仍然是一种好的做法,即使在非必要时也是如此。对于可移植的代码尤其如此。