2

我正在为我的第一个用 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;
}

和我的 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在二进制文件传输中是否会转义?如果不是,是什么导致了这种行为,我该如何解决这个问题?

4

2 回答 2

5

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

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

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

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

于 2013-06-02T19:52:06.827 回答
5

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

r/w 你应该很清楚, append 也很明显。在您的情况下,Trick & Trouble 是二进制模式。

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

在您的情况下,输入文件被读取为文本文件。这意味着,当从 HTTP-Data 读取文件时,所有的行尾都会被转换。

将文件作为二进制文件打开(确实如此!)避免了您的文件不再是二进制文件的麻烦。

于 2013-06-02T19:46:44.620 回答