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


C++ download binary file from http

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

  1. 程序发送它的版本到服务器php作为http头
  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();后刷新内容的方式,因此我不必在c++中解析它们。写入文件的第一个字节没有问题,所以我怀疑这里有任何问题。

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

问题:http在二进制文件传输中逃脱'r'n吗?如果不是,是什么导致了这种行为,我该如何解决这个问题?

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

你应该很清楚

r/w, append也很明显。魔术&;这里的问题是二进制模式。

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

在您的示例中,输入文件被作为文本文件读取。这意味着,在从HTTP-Data读取文件时,将转换所有行尾。

以二进制文件的形式打开文件(确实如此!)避免了文件不再是二进制文件的麻烦。

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

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

在Windows的文本模式下,在查找/读取时,ctrl+z字符指定文件的结尾,在写入时,换行字符'n被翻译为'r'n,在读取时,'r'n对被翻译为'n。在二进制模式下,不以任何方式解释或翻译文件数据。

在其他平台上,翻译可能不适用,但通过指定显式模式来显示代码的意图仍然是一个很好的实践,即使不是严格必要的。对于想要移植的代码尤其如此。