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

19g*_*g96 2 php c++ binary http

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

  1. 程序将其版本作为http标头发送到服务器php
  2. 服务器检查是否存在更高版本
  3. 如果是,则服务器将新二进制文件发送到客户端.

大多数都有效,但收到的二进制文件格式不正确.当我将格式错误的exe与工作exe进行比较时,我\r\n在编译的exe中有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;
}
Run Code Online (Sandbox Code Playgroud)

和我的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';


?>
Run Code Online (Sandbox Code Playgroud)

注意我发送标题后刷新内容的方式,ob_clean(); flush();所以我不必用c ++解析它们.写入文件的第一个字节很好,所以我怀疑这里有什么问题.

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

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

EGO*_*rds 5

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

r/w应该对你清楚,追加也很明显.你的案例中的诡计和麻烦是二元模式.

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

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

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


Ret*_*nja 5

问题是输出文件没有以二进制模式打开.要做到这一点,将模式更改为"wb"而不是"w",如下所示:

FILE *fp = fopen("update.exe", "wb");
Run Code Online (Sandbox Code Playgroud)

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

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