【问题标题】:How do I write images through HTTP in C?如何在 C 中通过 HTTP 编写图像?
【发布时间】:2013-02-07 16:48:56
【问题描述】:

刚才我通过连接写HTML内容没有问题。

    sprintf(toreturn, "%s\r\n%s\r\n%s\r\n\r\n%s", "HTTP/1.1 200 OK", "Content-Type: text/html", "Connection: close",htmlstring);
    write(*inputfd, toreturn, strlen(toreturn))

效果很好。但这就是我试图传递图像以响应图像请求的原因。在这种情况下,它适用于 .ico 文件,但我的问题代表任何二进制文件。

    FILE *writefile = (FILE *)calloc(1,sizeof(FILE));
    char *charptr = inputaddress;
    charptr++;
    writefile=fopen(charptr,"r");

    sprintf(toreturn, "%s\r\n%s\r\n%s\r\n\r\n", "HTTP/1.1 200 OK", "Content-Type: image/vnd.microsoft.icon", "Connection: close");
    write(*inputfd, toreturn, strlen(toreturn))
    write(*inputfd, *writefile, strlen(toreturn)
    close(*inputfd);
    fclose (writefile);

这不起作用。我如何在 C 中通过 HTTP write() 一个图像(或任何二进制文件)文件?

【问题讨论】:

  • 你不需要这个FILE *writefile = (FILE *)calloc(1,sizeof(FILE)); - FILE *writefile 就足够了。
  • calloc 不幸的是,他的问题最少......
  • 是的,我建议他看看sendfile,但他的问题远不止这些。

标签: c http networking network-programming


【解决方案1】:

处理二进制数据时不能使用 C 字符串函数。 C 字符串以 0 字节结尾,因此在任何可能包含二进制数据的字符串上使用 strlen() 都会返回截断的结果。

此外,您不能使用'*' 运算符来获取文件的内容。此外,您不应将FILE* 函数(fopen/fclose/fread/fwrite)与常规函数(open/close/read/write)混合使用,并且使用sprintf() 通常会自找麻烦 - 更安全的替代品是snprintf()

至于你必须做什么才能让它工作,你应该open()阅读图标,然后使用read()函数在循环中为你的缓冲区获取数据,直到返回的值小于0. 一个例子可以在这里找到:http://www.java-samples.com/showtutorial.php?tutorialid=569

【讨论】:

  • 这也是我的第一印象。但如果你仔细看,他并没有在二进制数据上使用 strlen 函数。它用于 HTTP 标头字符串。这对于第一次调用是正确的,但对于第二次调用是正确的。
  • @Vlad 啊,是的,你是对的,当他在sprintf() 调用中附加二进制数据时,我会以某种方式阅读它,并在那里遇到其他细节。感谢您在回答中总结所有其他问题:D。
【解决方案2】:

两个问题:

  1. 您必须在 HTTP 标头中输出内容长度标头。

  2. Writefile 不是你的图像的数据,你的代码所做的只是将文件描述符的内容输出到客户端。

正确的顺序应该是这样的

  1. 打开图标文件。
  2. 查询图标文件长度
  3. 创建您的 HTTP 标头,方法与您现在相同,但也包括 Content-Length 标头。
  4. 将文件内容读入缓冲区
  5. 将内容输出到输出套接字中。

注意,对于大文件,第 4 步和第 5 步必须写在循环中,否则会浪费内存。

【讨论】:

  • Magnus 有一个很好的观点,即使用低级函数更适合手头的任务。此外,linux 有一个低级内核函数'sendfile'kernel.org/doc/man-pages/online/pages/man2/sendfile.2.html,这对于这个任务将更有效。我认为Windows环境有类似的东西。
  • 附注:我认为 Content-Length 标头在 HTTP/1.1(或更低版本)中在技术上仍然是可选的。至少如果您在发送文件后立即关闭连接。当然,不包括它仍然是一个坏主意。为消息编写 HTTP/1.0 或 HTTP/0.9 前奏而不是 HTTP/1.1 可能也是一个好主意,因为这需要服务器支持更多的元数据。
【解决方案3】:

那么,你认为这段代码是做什么的?

writefile=fopen(charptr,"r");
...
write(*inputfd, *writefile, strlen(toreturn)

如果你说“写writefile 引用inputfd 的文件的内容”你就错了。

write 采用一个 buffer,其中包含您要写入的 实际 数据,并要求您指定要写入的字节数。您正在向它传递一个FILE(这不是函数所期望或需要的)并要求它写入与您的标头一样多的字节。

坦率地说,我很惊讶这甚至可以编译......

尝试打开您想要的文件,找出大小,分配适当大小的缓冲区,将内容读入所述缓冲区,关闭文件,然后将整个缓冲区发送给客户端。

【讨论】:

  • 谁修改了它?这实际上是一个合法的评论。
猜你喜欢
  • 2013-01-21
  • 2011-05-08
  • 1970-01-01
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
  • 2015-04-18
  • 1970-01-01
  • 2017-09-04
相关资源
最近更新 更多