2013-06-02 182 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。在二进制模式下,文件数据不会以任何方式解释或翻译。

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