2013-06-02 3 views
2

C++로 작성된 첫 번째 프로그램의 업데이트 메커니즘을 만들고 있습니다. 이론은 다음과 같습니다C++ HTTP에서 이진 파일 다운로드

  1. 프로그램은 최신 버전이, 실행하는 경우, 서버가 클라이언트에 새로운 바이너리를 전송
  2. 존재
  3. 서버를 확인하는 경우 HTTP 헤더로 서버의 PHP 버전에의 전송합니다.

대부분의 경우 작동하지만 수신 된 이진 형식이 잘못되었습니다. 조작 된 exe와 작동중인 exe를 비교할 때 컴파일 된 exe에서 \r\n이있는 곳에서 차이가 있습니다. \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을 탈출합니까? 그렇지 않은 경우이 문제의 원인은 무엇이며 어떻게이 문제를 해결할 수 있습니까?

+5

당신은 이진 출력 파일을 열어야합니다. 'fopen의 ("에서 update.exe", "WB");' –

+1

은 내가 C++ 전문가 모르겠지만, 데이터가 문자열이 그대로 메타 문자 대신으로 해석되는 것을 의미하는 이스케이프하지 않을 것으로 보인다. – Ohgodwhy

+0

@RetiredNinja는 매력처럼 작동합니다. 문제에 대한 설명이있는 대답이 크게 감사 할 것이고, 옳은 대답으로 받아 들여지고 받아 들여질 것입니다. – 19greg96

답변

5

fopen은 지정한 모드로 첫 번째 읽기/쓰기/양쪽 모두를 연 다음 추가, 이진 식별자를 엽니 다.

r/w는 분명해야하며, 분명히 추가해야합니다. 트릭 & 귀하의 경우 문제는 바이너리 모드입니다.

파일이 텍스트 파일 ("b"제외)로 처리되는 경우 응용 프로그램이 실행되는 환경에 따라 텍스트 모드의 입력/출력 작업에서 특수 문자 변환이 발생할 수 있습니다 시스템 고유의 텍스트 파일 형식. Windows의 경우 \ r \ n, Linux 시스템의 경우 \ n이고 일부 아키텍처의 경우에는 \ r이됩니다.

귀하의 경우, 입력 파일은 텍스트 파일로 읽습니다. 즉, HTTP-Data에서 파일을 읽을 때 모든 행 끝이 변환됩니다.

파일을 바이너리 파일로 열면 (사실!!) 파일이 더 이상 바이너리가 아닌 문제를 방지 할 수 있습니다.

+1

FWIW는'\ r'을 줄 끝으로 사용한 마지막 공통 운영체제로 고전적인 Mac OS는 10 년 전쯤에 사라졌습니다. Mac OS X은 다른 UNIX 시스템과 마찬가지로'\ n'을 사용합니다. – duskwuff

5

출력 파일이 바이너리 모드로 열리지 않는 것이 문제입니다. 줄 바꿈 Windows에서 텍스트 모드에서 Ctrl 키를

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

+/읽기를 추구 할 때 Z 문자는 파일의 끝을 지정하고 :이를 위해이 같은 모드 그냥 "w"대에 "WB"로 변경 문자 \ n은 \ r \ n으로 번역되고 \ r \ n 쌍은 \ n으로 변환됩니다. 바이너리 모드에서는 파일 데이터가 해석되거나 변환되지 않습니다.

번역이 적용되지 않을 수도 있습니다 다른 플랫폼에

,하지만 여전히도 꼭 필요한 것은 명시 적 모드를 지정하여 코드의 의도를 보여주는 것이 좋습니다. 이것은 특히 이식 가능한 코드에 해당됩니다.