2

C++ で書かれた最初のプログラムの更新メカニズムを作成しています。理論は次のとおりです。

  1. プログラムはそのバージョンをサーバーphpにhttpヘッダーとして送信します
  2. サーバーは新しいバージョンが存在するかどうかをチェックします
  3. 存在する場合、サーバーは新しいバイナリをクライアントに送信します。

ほとんどは機能しますが、受信したバイナリの形式が正しくありません。\r\n不正な形式の exe と動作中の exe を比較すると、コンパイルされた 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

fopen指定したモードでファイルを開きます。最初に読み取り/書き込み/両方、次に追加、次にバイナリ識別子です。

r/w は明らかです。append も非常に明白です。あなたの場合のトリック&トラブルはバイナリモードです。

ファイルがテキスト ファイル ("b" なし) として脅威にさらされている場合、アプリケーションが実行される環境によっては、テキスト モードでの入出力操作で特殊文字の変換が発生し、システム固有のファイルに適合させることがあります。テキストファイル形式。Windows ではこれは \r\n になり、Linux マシンでは \n になり、一部のアーキテクチャでは \r になります。

あなたの場合、入力ファイルはテキストファイルとして読み込まれます。これは、HTTP データからファイルを読み取るときに、すべての行末が変換されることを意味します。

ファイルをバイナリ ファイルとして開くと (実際にそうです!)、ファイルがまったく同じバイナリではないという問題を回避できます。

于 2013-06-02T19:46:44.620 に答える
5

問題は、出力ファイルがバイナリ モードで開かれていないことです。これを行うには、次のようにモードを「w」から「w」に変更します。

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

Windows のテキスト モードでは、シーク/読み取り時に ctrl+z 文字がファイルの末尾を指定し、書き込み時に改行文字 \n が \r\n に変換され、読み取り時に \r\n ペアが \n に変換されます。バイナリ モードでは、ファイル データはまったく解釈または変換されません。

他のプラットフォームでは翻訳が適用されない場合がありますが、厳密に必要でない場合でも、明示モードを指定してコードの意図を示すことをお勧めします。これは、移植性を意図したコードに特に当てはまります。

于 2013-06-02T19:52:06.827 に答える