C,HTTP响应数据的格式文件

时间:2013-09-11 05:45:05

标签: c file scanf

我没有使用fscanf()的经验,也没有FILE的功能。我有正确的代码来确定客户端是否请求了现有文件(使用stat()并确保它不是目录)。我将省略这一部分,因为它工作正常。

我的目标是使用HTTP标头(字符串)和正确读取的数据将字符串发送回客户端,我认为这些数据在某些时候必须成为字符串以与发送回的标头连接。我知道+无效C,但为了简单起见,我想发送此信息:headerString+dataString

下面的代码似乎适用于文本文件,但不适用于图像。我希望单独阅读每个角色可以解决问题,但事实并非如此。当我在我的服务器上指向浏览器(Firefox)寻找图像时,它告诉我“图像(图像的名称)无法显示,因为它包含错误。”。

这是应该将文件读入httpData的代码:

int i = 0;
FILE* file;
file = fopen(fullPath, "r");
if (file == NULL) errorMessageExit("Failed to open file");
while(!feof(file)) {
    fscanf(file, "%c", &httpData[i]);
    i++;
}
fclose(file);
printf("httpData = %s\n", httpData);

修改:这是我发送的内容:

char* httpResponse = malloc((strlen(httpHeader)+strlen(httpData)+1)*sizeof(char));
strcpy(httpResponse, httpHeader);
strcat(httpResponse, httpData);
printf("HTTP response = %s\n", httpResponse);

数据部分产生????对于图像,但正确的html为HTML文件。

1 个答案:

答案 0 :(得分:1)

图片包含二进制数据。 256个不同的8位模式中的任何一个可以出现在图像中,尤其包括空字节0x00或'\0'。在某些系统(尤其是Windows)上,您需要使用标准I / O b调用中的字母fopen()来区分文本文件和二进制文件(在Unix和Windows上都能正常工作)。鉴于二进制数据可以包含空字节,您不能使用strcpy()等来复制数据块,因为str*()函数在第一个空字节处停止复制。因此,您必须使用mem*()函数来获取起始位置和长度,或等效函数。

应用于您的代码,使用httpData打印二进制%s将无法正常工作; %s将停在第一个空字节处。由于您已使用stat()来验证文件是否存在,因此您还拥有该文件的大小。假设您不必处理动态更改的文件,这意味着您可以将httpData分配为正确的大小。您也可以将大小传递给阅读代码。这也意味着读取代码可以使用fread(),编写代码可以使用fwrite(),从而节省逐个字符的I / O.

因此,我们可能有一个功能:

int readHTTPData(const char *filename, size_t size, char *httpData)
{
    FILE *fp = fopen(filename, "rb");
    size_t n;
    if (fp == 0)
        return E_FILEOPEN;
    n = fread(httpData, size, 1, fp);
    fclose(fp);
    if (n != 1)
        return E_SHORTREAD;
    fputs("httpData = ", stdout);
    fwrite(httpData, size, 1, stdout);
    putchar('\n');
    return 0;
}

该函数在成功时返回0,并在失败时返回一些预定义的(负?)错误号。由于内存分配是在调用例程之前完成的,因此非常简单:

  • 打开文件;如果失败则报告错误。
  • 只需一次操作即可阅读该文件。
  • 关闭文件。
  • 如果读取未获得预期的所有数据,则报告错误。
  • 报告所读取的数据(仅调试 - 将二进制数据打印到标准输出原始数据并不是世界上最好的想法,但它与问题中的代码相似)。
  • 成功报道。

在原始代码中,有一个循环:

int i = 0;
...
while(!feof(file)) {
    fscanf(file, "%c", &httpData[i]);
    i++;
}

这个循环有很多问题:

  1. 您不应使用feof()来测试是否有更多数据需要阅读。它会报告是否已给出EOF指示 ,而不是是否
  2. 因此,当读取完最后一个字符时,feof()报告'false',但fscanf()尝试读取下一个(不存在的)字符,将其添加到缓冲区(可能如a,y-umlaut,0xFF,U + 00FF,带有DIAERESIS的LATIN SMALL LETTER字母。
  3. 代码不会检查已读取的字符数,因此无法防止缓冲区溢出。
  4. fscanf()相比,使用getc()读取单个字符需要大量开销。
  5. 这是一个更接近正确的代码版本,假设size是分配给httpData的字节数。

    int i = 0;
    int c;
    
    while ((c = getc(file)) != EOF && i < size)
        httpData[i++] = c;
    

    您可以在预期时检查是否获得了EOF。请注意,fread()代码会在fread()函数中执行大小检查。此外,我编写参数的方式,它是一个全有或全无的命题 - 要么读取所有size个字节,要么将所有字节视为缺失。如果您想要字节计数并且愿意容忍或处理短读取,则可以反转大小参数的顺序。你也可以检查fwrite()的回报,如果你想确定它是全部写的,但是人们往往不太注意检查输出是否成功。 (但是,检查您是否获得了预期的输入几乎总是至关重要的 - 不要吝啬输入检查。)

    在某些时候,对于纯文本数据,您需要考虑CRLF与NL行结尾。文本文件自动处理;二进制文件没有。如果要传输的数据是image/png或类似的东西,您可能不需要担心这一点。如果你在Unix上处理text/plain,你可能不得不担心CRLF行结尾(但我不是这方面的专家 - 我最近没有做过低级HTTP的事情(不是这个)千禧年,所以规则可能已经改变了。)