2013-06-02 61 views
2

我創建了我用C++編寫的第一個程序的更新機制。 理論是:C++從http下載二進制文件

  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?如果不是,是什麼導致了這種行爲,我該如何解決這個問題?

+5

您應該以二進制格式打開輸出文件。 'fopen(「update.exe」,「wb」);' –

+1

我不是一個C++大師,但似乎數據並沒有被轉義,這意味着字符串將被解釋爲元字符而不是字面意思。 – Ohgodwhy

+0

@RetiredNinja就像一個魅力,解答問題的答案將不勝感激,投票並接受爲正確的答案。 – 19greg96

回答

5

fopen打開在你指定的模式文件,首先讀/寫/兩,然後附加,然後一個二進制標識符。

R/W應該清楚了你,追加也相當明顯。訣竅&在你的情況下的麻煩是二進制模式。

如果文件被視爲文本文件(不帶「b」),那麼根據應用程序運行的環境,文本模式中的輸入/輸出操作可能會發生一些特殊字符轉換,以適應它們系統特定的文本文件格式。在Windows上,這將是\ r \ n,在您擁有\ n並且存在某些體系結構的Linux機器上,它位於\ r。

在你的情況下,輸入文件被讀爲文本文件。這意味着,從HTTP-Data中讀取文件時,所有行尾都會被轉換。

打開該文件爲二進制文件(至極的確是!)避免麻煩,你的文件是不是二進制相同了。

+1

FWIW,最後一個使用'\ r'作爲行結尾的常見操作系統是經典的Mac OS,它在十年前就消失了。像其他UNIX系統一樣,Mac OS X使用'\ n'。 – duskwuff

5

的問題是,輸出文件不被以二進制模式打開。在Windows

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

在文本模式下,CTRL +尋找/讀取時Z字符指定文件的末尾,和換行:要做到這一點,將模式更改爲「WB」而不只是「W」這樣的字符\ n在寫入時被轉換爲\ r \ n,並且\ r \ n對在讀取時被轉換爲\ n。在二進制模式下,文件數據不會以任何方式解釋或翻譯。

在其他平臺上,翻譯可能不適用,但通過指定顯式模式來顯示代碼的意圖仍然是一種很好的做法,即使並非絕對必要。對於意味着便攜式的代碼尤其如此。