Отправить двоичный файл в ответ HTTP, используя сокеты C - PullRequest
7 голосов
/ 31 марта 2011

Я пытаюсь отправить двоичный файл (изображение png) в ответ http.

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: я пытался отправить текстовые данные - все в порядке. Но двоичные данные не удается

Ответы [ 4 ]

8 голосов
/ 31 марта 2011

Проблема в том, что ваше тело сообщения обрабатывается как текстовая строка с нулевым символом в конце (вы используете strcat и strlen для нее), когда она не одна: это двоичные данные (файл 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.

Другая ошибка заключается в том, что вы не закрываете соединение, когда закончите, поэтому браузер будет ждать вечно. Вам это нужно после send:

close(client);
1 голос
/ 31 марта 2011

Протокол HTTP указывает, что он ожидает "\ r \ n" вместо "\ n". Попробуй это. :)

0 голосов
/ 22 декабря 2017

Я пытался следовать тому, что ты сделал, но не смог заставить его работать.Вместо этого мне было проще отправлять заголовок и файл отдельно.

например

send(client, header, strlen(header), 0);
send(client, buffer, fileLen + 1, 0);
0 голосов
/ 31 марта 2011
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
...