2012-01-29 72 views
2

在网络分配中存在一些问题。最终目标是拥有一个C程序,通过HTTP从给定的URL抓取文件并将其写入给定的文件名。对于大多数文本文件我都能正常工作,但我遇到了一些问题,我怀疑这些问题都来自同一根本原因。未知文件类型的C文件输入/输出:文件复制

下面是我使用从网络文件描述符将数据传输到输出文件描述符的代码的快速版本:

unsigned long content_length; // extracted from HTTP header 
unsigned long successfully_read = 0; 
while(successfully_read != content_length) 
{ 
    char buffer[2048]; 
    int extracted = read(connection,buffer,2048); 
    fprintf(output_file,buffer); 
    successfully_read += extracted; 
} 

正如我所说的,这工作对大多数的文本文件(尽管%符号会混淆fprintf,所以有办法解决这个问题会很好)。问题在于,当我尝试获取非文本文件时(.png是我正在使用的基本测试文件,但该程序需要能够处理任何内容),它会永久挂起。

我做了一些调试和我知道我不会在CONTENT_LENGTH,在读期间收到错误,或者打一些网络瓶颈。我在网上查了一下,但是我可以找到的二进制文件的所有C文件I/O代码似乎都基于这样的想法,即您知道文件中的数据是如何构建的。我不知道它的结构如何,我也不太在乎;我只想将一个文件描述符的内容复制到另一个文件描述符中。

任何人都可以指向我往一些内置的文件I/O功能,我可以打棍子投入使用为目的?

编辑:或者,有没有在HTTP标头会告诉我如何处理任何文件我正在使用一个标准的领域?

+1

使用'fprintf中()'那样是危险的;这是一个安全漏洞,称为“格式字符串漏洞”。你可以用'fprintf中(OUTPUT_FILE“%s”,缓冲区);'如果你有信心,再也不会有NUL''在数据\ 0''字节;否则,使用'fwrite()'。 – 2012-01-29 00:40:25

回答

4

您正在使用错误的工作工具。 fprintf需要一个格式字符串和额外的参数,比如:

fprintf(output_file, "hello %s, today is the %d", cstring, dayoftheweek); 

如果从未知来源传递的第二个参数(如网页,你正在做的),你可以不小心有%s%d或其他格式说明在字符串中。然后fprintf将尝试读取比传递更多的参数,并导致未定义的行为。

使用fwrite此:

fwrite(buffer, 1, extracted, output_file); 
+0

完美的工作,谢谢Seth! – 2012-01-31 18:40:49

1

有两件事情与您的代码:

对于fprintf中 - 您正在使用的数据作为第二个参数,而实际上它应该是格式,数据应该是第三个参数。这就是为什么你遇到%字符的问题,以及为什么当呈现二进制数据时它会挣扎,因为它需要一个格式字符串。

您需要使用不同的功能,如FWRITE,输出文件。

作为一个方面说明,这是一个有点安全问题的 - 如果你从服务器获取特制的文件有可能暴露你的内存随机领域。

0

除了Seth的回答:除非您使用第三方库来处理所有的HTTP内容,否则您需要处理Transfer-Encoding标头和可能的压缩,或者至少检测它们并发出错误,如果您不知道如何处理这种情况。

一般情况下,它可能(或可能不是)来解析HTTP响应头是个好主意,并且仅当它们包含独占你了解的东西,你应该继续解释下面的标题中的数据。

+0

检查传输编码的好主意。尽管如此,我认为我们预计不会这样做。那是HTTP 1.1的东西,而不是服务器应该用HTTP 1.0格式的响应来响应HTTP 1.0请求? – 2012-01-31 18:15:42

0

我敢打赌,你的程序挂起是因为它期望X字节,但是接收Y而不是X,其中Y为< Y(很可能是无压缩 - 但PNG不能很好地压缩到gzip)。你会得到大块[*]数据,与块的一个最有可能跨越content_length以使条件while(successfully_read != content_length)始终为真。

如果你想看看你的程序如何继续尝试读取它永远不会得到的数据,你可以试着在strace或其它任何与你的操作系统相同的程序上运行你的程序(因为你可能提出了HTTP/1.1请求保持连接打开,而你还没有做出第二个请求)或已结束(如果服务器关闭连接,你的(重复)调用,读取(2)将只返回0,这让你的(还是true)循环条件不变

如果您将程序的输出发送到标准输出,您可能会发现它不会产生输出 - 如果您正在检索的资源不包含换行符或其他强制刷新控制字符,则会发生这种情况。可能适用于输出到文件时或例如,该文件将直到标准输入输出缓冲器具有累积至少4096字节保留为空。)

[*]然后也有Transfer-Encoding: chunked,如@罗兰ILLIG暗示,这将破坏content_length之间的确切等价(大概来自同名HTTP头)以及通过套接字传输的实际字节数。

+0

一些很好的想法,但我肯定会发送一个HTTP/1.0请求,并且我已经在循环中进行了一些调试检查,这些检查在我的原始文章中没有显示在示例中,所以我知道我没有收到更多数据超出预期。 – 2012-01-31 18:10:51

0

您正在打开该文件为文本文件。这样做意味着程序会在每次write()调用结束时添加\ r \ n字符。尝试打开文件作为二进制文件,这些错误的大小将消失。