我正在为我用c++编写的第一个程序创建一个更新机制。理论是:
- 程序发送它的版本到服务器php作为http头
- 服务器检查是否存在更高版本
- 如果是,服务器发送新的二进制文件给客户端。
大部分工作,但二进制接收是畸形的。当我将畸形的exe与工作的exe进行比较时,我在编译的exe中有'r'n
s的地方有差异。似乎'r
是双倍的。
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
吗?如果不是,是什么导致了这种行为,我该如何解决这个问题?
fopen
以指定的模式打开文件,首先读/写/两者,然后追加,然后是二进制标识符。
r/w, append也很明显。魔术&;这里的问题是二进制模式。
如果文件被威胁为文本文件(没有"b"),则根据应用程序运行的环境,在文本模式下的输入/输出操作中可能会发生一些特殊的字符转换,以使其适应特定于系统的文本文件格式。在Windows上是'r'n,在linux机器上是'n,在某些架构上是'r。
在您的示例中,输入文件被作为文本文件读取。这意味着,在从HTTP-Data读取文件时,将转换所有行尾。
以二进制文件的形式打开文件(确实如此!)避免了文件不再是二进制文件的麻烦。
问题是输出文件不是以二进制模式打开的。要做到这一点,将模式更改为"wb"而不是"w",如下所示:
FILE *fp = fopen("update.exe", "wb");
在Windows的文本模式下,在查找/读取时,ctrl+z字符指定文件的结尾,在写入时,换行字符'n被翻译为'r'n,在读取时,'r'n对被翻译为'n。在二进制模式下,不以任何方式解释或翻译文件数据。
在其他平台上,翻译可能不适用,但通过指定显式模式来显示代码的意图仍然是一个很好的实践,即使不是严格必要的。对于想要移植的代码尤其如此。