使用 C 套接字在 HTTP 响应中发送二进制文件

发布于 2024-10-28 13:11:23 字数 1582 浏览 3 评论 0原文

我正在尝试在 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:我尝试发送文本数据 - 没问题。但是二进制数据失败

I`m trying to send a binary file (png image) in http response.

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);
    }
}

but my browser does not understand this =( What am I doing wrong exactly?

UPD: I tried to send text data - its OK. But binary data fails

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

旧城烟雨 2024-11-04 13:11:23

问题是您的消息正文被视为以 null 结尾的文本字符串(您在其上使用 strcatstrlen),而它不是一个:它是二进制数据(PNG 文件)。因此,strcat 和 strlen 都停止在图像中的第一个 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

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

close(client);

The problem is that your message body is being treated as a null-terminated text string (you use strcat and strlen on it), when it isn't one: it is binary data (a PNG file). Therefore, strcat and strlen both stop on the first 0 byte in the image (typically quite early).

Your program is even printing out the response body: notice that it gives the correct header, but that once the PNG header (binary data) starts, there is only a few bytes.

  1. The line strcat(reply, buffer), where buffer potentially contains 0 bytes. Change it to memcpy(reply+strlen(header), buffer, fileLen).
  2. The line send(client, reply, strlen(reply), 0), where reply potentially contains 0 bytes. Pre-calculate the length of the reply, or replace the strlen with strlen(header)+fileLen.

Another bug is that you aren't closing the connection when you're done, so the browser will just wait forever. You need this, after send:

close(client);
请持续率性 2024-11-04 13:11:23

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

The HTTP protocol specifies that it expects "\r\n" instead of "\n". Try that. :)

天荒地未老 2024-11-04 13:11:23
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(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
顾忌 2024-11-04 13:11:23

我试图按照你所做的去做,但无法让它发挥作用。相反,我发现单独发送标头和文件更容易。

例如

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

I tried to follow what you did but could not get it to work. Instead, I found it easier to just send header and file separately.

e.g.

send(client, header, strlen(header), 0);
send(client, buffer, fileLen + 1, 0);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文