【问题标题】:Send binary file in HTTP response using C sockets使用 C 套接字在 HTTP 响应中发送二进制文件
【发布时间】:2011-07-26 15:43:48
【问题描述】:

我正在尝试在 http 响应中发送二进制文件(png 图像)。

FILE *file;
char *buffer;
int fileLen;

//Open file
file = fopen("1.png", "rb");
if (!file)
{
    return;
}

//Get file length
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);

//Allocate memory
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
    fprintf(stderr, "Memory error!");
    fclose(file);
    return;
}

//Read file contents into buffer
fread(buffer, fileLen, 1, file);
fclose(file);
//free(buffer);




char header[102400];

sprintf(header, 
"HTTP/1.1 200 OK\n"
"Date: Thu, 19 Feb 2009 12:27:04 GMT\n"
"Server: Apache/2.2.3\n"
"Last-Modified: Wed, 18 Jun 2003 16:05:58 GMT\n"
"ETag: \"56d-9989200-1132c580\"\n"
"Content-Type: image/png\n"
"Content-Length: %i\n"
"Accept-Ranges: bytes\n"
"Connection: close\n"
        "\n", fileLen);

char *reply = (char*)malloc(strlen(header)+fileLen);
strcpy(reply, header);
strcat(reply, buffer);

printf("msg %s\n", reply);


//return 0;
int sd = socket(PF_INET, SOCK_STREAM, 0);

struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8081);
addr.sin_addr.s_addr = INADDR_ANY;

if(bind(sd,&addr,sizeof(addr))!=0)
{
    printf("bind error\n");
}

if (listen(sd, 16)!=0)
{
    printf("listen error\n");
}

for(;;)
{
    int size = sizeof(addr);
    int client = accept(sd, &addr, &size);

    if (client > 0)
    {
        printf("client connected\n");
        send(client, reply, strlen(reply), 0);
    }
}

但是我的浏览器不理解这个=(我到底做错了什么?

UPD:我尝试发送文本数据 - 没问题。但二进制数据失败

【问题讨论】:

    标签: c http sockets binary send


    【解决方案1】:

    问题是您的消息正文被视为以空字符结尾的文本字符串(您在其上使用 strcatstrlen),而它不是一个:它是二进制数据(PNG 文件) .因此,strcatstrlen 都在图像的第一个 0 字节处停止(通常很早)。

    您的程序甚至打印出响应正文:请注意它提供了正确的标头,但是一旦 PNG 标头(二进制数据)开始,只有几个字节。

    1. strcat(reply, buffer) 行,其中buffer 可能包含 0 个字节。将其更改为memcpy(reply+strlen(header), buffer, fileLen)
    2. send(client, reply, strlen(reply), 0) 行,其中reply 可能包含 0 个字节。预先计算回复的长度,或者将strlen替换为strlen(header)+fileLen

    另一个错误是您在完成后没有关闭连接,因此浏览器将永远等待。你需要这个,在send之后:

    close(client);
    

    【讨论】:

    • 请注意,这实际上不会修复您输入的调试打印,因为它使用 printf 并且会在遇到空字节时停止。但是套接字行为将是正确的;我在网络浏览器中对此进行了测试,并且成功了。
    【解决方案2】:

    HTTP 协议指定它需要“\r\n”而不是“\n”。试试看。 :)

    【讨论】:

    • 不,这没有帮助。我尝试发送文本数据 - 使用“\n”可以。但二进制数据失败
    • Windows 在输出时自动将 \n 转换为 \r\n
    【解决方案3】:
    strcat(reply, buffer); // this is incorrect, because png(buffer) may contain zero byte
    send(client, reply, strlen(reply), 0);
    strlen(reply) // this is incorrect, because png may contain zero byte
    

    【讨论】:

    • 不仅如此;请注意,从缓冲区到回复的strcat 在遇到空字节时也会失败 - 请参阅我的答案。
    【解决方案4】:

    我尝试按照您的操作进行操作,但无法使其正常工作。相反,我发现单独发送标头和文件更容易。

    例如

    send(client, header, strlen(header), 0);
    send(client, buffer, fileLen + 1, 0);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 2020-02-25
      • 2012-08-23
      • 1970-01-01
      • 1970-01-01
      • 2013-01-08
      • 2013-09-10
      相关资源
      最近更新 更多