我正在为我用c ++编写的第一个程序创建一个更新机制。 理论是:
但是大部分都有效,但收到的二进制文件格式不正确。当我将格式错误的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
?如果不是,导致此行为的原因是什么?如何解决此问题?
答案 0 :(得分:5)
fopen
以您指定的模式打开文件,首先读/写/两者,然后追加,然后是二进制标识符。
如果文件被作为文本文件(没有“b”)进行威胁,则根据应用程序运行的环境,在文本模式下的输入/输出操作中可能会发生一些特殊的字符转换,以使它们适应系统特定的文本文件格式。在Windows上,这将是\ r \ n,在Linux机器上你有\ n并且在某些架构上存在,它是\ r \ n。
在您的情况下,输入文件将作为文本文件读取。这意味着,从HTTP数据中读取文件时,所有行结尾都会被转换。
将文件作为二进制文件打开(实际上是!),避免了文件不再具有二进制文件的麻烦。
答案 1 :(得分:5)
问题是输出文件没有以二进制模式打开。为此,将模式更改为“wb”而不是“w”,如下所示:
FILE *fp = fopen("update.exe", "wb");
在Windows上的文本模式下,ctrl + z字符指定搜索/读取时文件的结尾,并且在写入时将换行符\ n转换为\ r \ n,并将\ r \ n对转换为\ n在阅读。在二进制模式下,不会以任何方式解释或翻译文件数据。
在其他平台上,翻译可能不适用,但通过指定显式模式来显示代码的意图仍然是一种好的做法,即使在非必要时也是如此。对于可移植的代码尤其如此。