将图像写成C中的插座

发布于 2025-01-29 02:24:53 字数 3268 浏览 2 评论 0原文

我制作了可以将HTML提供给浏览器的服务器,但是由于某种原因,它不会发送图像。每当我在插座上发送图像时,浏览器都会收到一些图像,例如指定格式的标题,但图像的主体为/00/00/00/00仅为null字符。

这是代码:(我只是将响应标头从content-type:text/html更改为image/gif,所以忽略了变量的名称,我知道这是错误的。)

/*Refer to documentation for questions and functionality, as well as limitations*/
/*I have given each section of code an index in the form of a comment, which you can refer to in the documentation*/
#include <arpa/inet.h>  /* htons() htonl()          */
#include <unistd.h>     /* read() write()           */
#include <stdlib.h>     /* exit()                   */
#include <string.h>     /* strlen() strcat()        */
#include <stdio.h>      /* FILE scanf() printf()    */

int main(void)
{
    /*startof[a]*/
    char filename[256];
    FILE *file_pointer;
    unsigned int file_size;
    unsigned short int port_number;
    struct sockaddr_in listening_socket_address;
    int socket_address_size;
    int listening_socketfd;
    int new_socketfd;
    struct sockaddr_in new_socket_address;
    char HTTP_REQUEST[8192];
    char file_buffer[2097152];
    char HTTP_TEXT_RESPONSE_HEADER[] = "HTTP/1.0 200 OK\nContent-Type: image/*\n\n";
    char HTTP_RESPONSE[2097152];
    int response_size;
    /*endof[a]*/
    
    /*startof[b]*/
    printf("Please enter the name of the file (text formats only) to be transmitted today, you can give a whole path, or just the name if it is in the same directory as this program :)\nFilename: ");
    scanf("%255s", filename);
    file_pointer = fopen(filename, "r");
    fseek(file_pointer, 0L, SEEK_END);
    file_size = ftell(file_pointer);
    printf("File: %s is Size: %d Bytes\n", filename, file_size);
    rewind(file_pointer);
    printf("File: %s has been rewinded to position: 0\n\n", filename);
    /*endof[b]*/
    
    /*startof[c]*/
    printf("Enter port number: ");
    scanf("%hu", &port_number);
    
    listening_socket_address.sin_family = AF_INET;
    listening_socket_address.sin_port = htons(port_number);
    listening_socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
    
    socket_address_size = sizeof(listening_socket_address);
    /*endof[c]*/
    
    /*startof[d]*/
    listening_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    bind(listening_socketfd, (struct sockaddr *) &listening_socket_address, socket_address_size);
    listen(listening_socketfd, 1);
    new_socketfd = accept(listening_socketfd, (struct sockaddr *) &new_socket_address, &socket_address_size);
    /*endof[d]*/
    
    /*startof[e]*/
    read(new_socketfd, HTTP_REQUEST, 8192);
    printf("\nHere is the HTTP Request:\n\n%s", HTTP_REQUEST);
    /*endof[e]*/
    
    /*startof[f]*/
    fread(file_buffer, 1, file_size, file_pointer);
    
    strcat(HTTP_RESPONSE, HTTP_TEXT_RESPONSE_HEADER);
    strncat(HTTP_RESPONSE, file_buffer, file_size);
    
    response_size = sizeof(HTTP_TEXT_RESPONSE_HEADER) + file_size;
    
    write(new_socketfd, (char*)HTTP_RESPONSE, response_size);
    close(new_socketfd);
    
    printf("Here is the HTTP response:\n\n%s", HTTP_RESPONSE);
    /*endof[f]*/
    
    return 0;
}

我正在使用的图像是GIF89A,并且浏览器能够说它是GIF89A,但是GIF内部的所有实际数据都是空字符。

我认为也许是因为图像是二进制的,因此它被浏览器(Firefox)使用的某些怪异格式/字节订单不事件砸碎,出于可移植性原因,我需要将其变成base64。

I made a server that can serve html to a browser, but for some reason it wont send images. Every time I send an image over the socket, the browser receives some of the image, like the headers specifying the format, but the body of the image is all /00/00/00 just null characters.

Here is the code: (I just changed the response header from content-type: text/html to image/gif, so ignore the name of the variable, I know it is wrong.)

/*Refer to documentation for questions and functionality, as well as limitations*/
/*I have given each section of code an index in the form of a comment, which you can refer to in the documentation*/
#include <arpa/inet.h>  /* htons() htonl()          */
#include <unistd.h>     /* read() write()           */
#include <stdlib.h>     /* exit()                   */
#include <string.h>     /* strlen() strcat()        */
#include <stdio.h>      /* FILE scanf() printf()    */

int main(void)
{
    /*startof[a]*/
    char filename[256];
    FILE *file_pointer;
    unsigned int file_size;
    unsigned short int port_number;
    struct sockaddr_in listening_socket_address;
    int socket_address_size;
    int listening_socketfd;
    int new_socketfd;
    struct sockaddr_in new_socket_address;
    char HTTP_REQUEST[8192];
    char file_buffer[2097152];
    char HTTP_TEXT_RESPONSE_HEADER[] = "HTTP/1.0 200 OK\nContent-Type: image/*\n\n";
    char HTTP_RESPONSE[2097152];
    int response_size;
    /*endof[a]*/
    
    /*startof[b]*/
    printf("Please enter the name of the file (text formats only) to be transmitted today, you can give a whole path, or just the name if it is in the same directory as this program :)\nFilename: ");
    scanf("%255s", filename);
    file_pointer = fopen(filename, "r");
    fseek(file_pointer, 0L, SEEK_END);
    file_size = ftell(file_pointer);
    printf("File: %s is Size: %d Bytes\n", filename, file_size);
    rewind(file_pointer);
    printf("File: %s has been rewinded to position: 0\n\n", filename);
    /*endof[b]*/
    
    /*startof[c]*/
    printf("Enter port number: ");
    scanf("%hu", &port_number);
    
    listening_socket_address.sin_family = AF_INET;
    listening_socket_address.sin_port = htons(port_number);
    listening_socket_address.sin_addr.s_addr = htonl(INADDR_ANY);
    
    socket_address_size = sizeof(listening_socket_address);
    /*endof[c]*/
    
    /*startof[d]*/
    listening_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    bind(listening_socketfd, (struct sockaddr *) &listening_socket_address, socket_address_size);
    listen(listening_socketfd, 1);
    new_socketfd = accept(listening_socketfd, (struct sockaddr *) &new_socket_address, &socket_address_size);
    /*endof[d]*/
    
    /*startof[e]*/
    read(new_socketfd, HTTP_REQUEST, 8192);
    printf("\nHere is the HTTP Request:\n\n%s", HTTP_REQUEST);
    /*endof[e]*/
    
    /*startof[f]*/
    fread(file_buffer, 1, file_size, file_pointer);
    
    strcat(HTTP_RESPONSE, HTTP_TEXT_RESPONSE_HEADER);
    strncat(HTTP_RESPONSE, file_buffer, file_size);
    
    response_size = sizeof(HTTP_TEXT_RESPONSE_HEADER) + file_size;
    
    write(new_socketfd, (char*)HTTP_RESPONSE, response_size);
    close(new_socketfd);
    
    printf("Here is the HTTP response:\n\n%s", HTTP_RESPONSE);
    /*endof[f]*/
    
    return 0;
}

The image I am using is a gif89a, and the browser is able to tell it is a gif89a, but all the actual data inside the gif is just null characters.

I am thinking that perhaps because the image is in binary, it is being smashed by some weird formatting/ byte order mishap that the browser(firefox) is using, an I need to turn it into base64 for portability reasons.

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

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

发布评论

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

评论(1

不回头走下去 2025-02-05 02:24:53

此代码有很多错误,但最重要的是,您根本没有发送有效的HTTP响应:

  • 您必须使用\ r \ n进行换行。

  • 图像/*不是单个文件的有效媒体类型,使用更合适的媒体类型,例如image/gif等。

  • 您缺少<

    代码> content-Length 标题指定图像的大小,因为您没有使用HTTP的传输编码。

  • 请勿使用sizef(http_text_response_header),其中包括null-terminator。使用strlen()而不是。

  • 不要使用strncat() binary 数据附加到char [] array。这将破坏第一个0x00遇到的字节。

  • binary 模式打开图像文件。

  • 不要尝试write()单个发送中的全部 http响应。那根本不起作用。内核缓冲区可能不够大,无法将其全部发送。接收器的内核缓冲区可能不够大,无法接收全部。您需要注意write()的返回值,这将告诉您内核实际接受了多少个字节以发送。调用write()在循环中,直到所有字节都被接受为止。

话虽如此,请尝试更多类似的东西:

/*Refer to documentation for questions and functionality, as well as limitations*/
/*I have given each section of code an index in the form of a comment, which you can refer to in the documentation*/
#include <arpa/inet.h>  /* htons() htonl()          */
#include <unistd.h>     /* read() write()           */
#include <stdlib.h>     /* exit()                   */
#include <string.h>     /* strlen() strcat()        */
#include <stdio.h>      /* FILE scanf() printf()    */

int write_all(int fd, const void *data, size_t data_size)
{
    char *ptr = (const char*) data;
    ssize_t written;

    while (data_size > 0)
    {
        written = write(fd, ptr, data_size);
        if (written < 0) return -1;
        ptr += written;
        data_size -= written;
    }

    return 0;
}

int main(void)
{
    /*startof[a]*/
    char filename[256];
    FILE *file_pointer;
    unsigned int file_size;
    unsigned short int port_number;
    struct sockaddr_in listening_socket_address;
    int socket_address_size;
    int listening_socketfd;
    int new_socketfd;
    struct sockaddr_in new_socket_address;
    char HTTP_REQUEST[8192];
    char HTTP_RESPONSE_HEADER[128];
    char HTTP_RESPONSE_HEADER_FMT[] = "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %u\r\nConnection: close\r\n\r\n";
    char file_buffer[1024];
    char media_type[] = "image/gif";
    int request_size;
 response_size;
    /*endof[a]*/
    
    /*startof[b]*/
    printf("Please enter the name of the file (text formats only) to be transmitted today, you can give a whole path, or just the name if it is in the same directory as this program :)\nFilename: ");
    scanf("%255s", filename);
    file_pointer = fopen(filename, "rb");
    if (!file_pointer) {
        // display error message...
        return -1;
    }
    fseek(file_pointer, 0L, SEEK_END);
    file_size = ftell(file_pointer);
    printf("File: %s is Size: %u Bytes\n", filename, file_size);
    rewind(file_pointer);
    printf("File: %s has been rewinded to position: 0\n\n", filename);

    // TODO: set media_type to appropriate type
    // based on what kind of file is being sent...
    /*endof[b]*/
    
    /*startof[c]*/
    printf("Enter port number: ");
    scanf("%hu", &port_number);
    
    memset(&listening_socket_address, 0, sizeof(listening_socket_address));
    listening_socket_address.sin_family = AF_INET;
    listening_socket_address.sin_port = htons(port_number);
    listening_socket_address.sin_addr.s_addr = htonl(INADDR_ANY);    
    /*endof[c]*/
    
    /*startof[d]*/
    listening_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listening_socketfd < 0) {
        // display error message...
        return -1;
    }
    if (bind(listening_socketfd, (struct sockaddr *) &listening_socket_address, sizeof(listening_socket_address)) < 0) {
        // display error message...
        return -1;
    }
    if (listen(listening_socketfd, 1) < 0) {
        // display error message...
        return -1;
    }
    socket_address_size = sizeof(new_socket_address);
    new_socketfd = accept(listening_socketfd, (struct sockaddr *) &new_socket_address, &socket_address_size);
    if (new_socketfd < 0) {
        // display error message...
        return -1;
    }
    /*endof[d]*/
    
    /*startof[e]*/
    // TODO: read client's request per HTTP protocol...
    request_size = read(new_socketfd, HTTP_REQUEST, 8192);
    if (request_size < 0) {
        // display error message...
        return -1;
    }
    printf("\nHere is the HTTP Request:\n\n%.*s", request_size, HTTP_REQUEST);
    /*endof[e]*/
    
    /*startof[f]*/
    response_size = sprintf(HTTP_RESPONSE_HEADER, HTTP_RESPONSE_HEADER_FMT, media_type, file_size);
    printf("Here is the HTTP response:\n\n%s", HTTP_RESPONSE_HEADER);

    if (write_all(new_socketfd, HTTP_RESPONSE_HEADER, response_size) < 0) {
        return -1;
    }

    while (file_size > 0) {
        response_size = fread(file_buffer, 1, min(file_size, sizeof(file_buffer)), file_pointer);
        if (response_size < 1) break;
        if (write_all(new_socketfd, file_buffer, response_size) < 0) break;
        file_size -= response_size;
    }
    
    close(new_socketfd);
    /*endof[f]*/
    
    close(listening_socketfd);
    return 0;
}

There are a lot of things wrong with this code, but most importantly, you are simply not sending a valid HTTP response:

  • You must use \r\n for line breaks.

  • image/* is not a valid media type for a single file, use a more appropriate media type, like image/gif, etc.

  • You are missing a Content-Length header to specify the image's size, since you are not using HTTP's chunked transfer encoding.

  • Do not use sizeof(HTTP_TEXT_RESPONSE_HEADER), which includes the null-terminator. Use strlen() instead.

  • Don't use strncat() to append binary data to a char[] array. That will break on the first 0x00 byte encountered.

  • Open image files in binary mode.

  • Don't try to write() the entire HTTP response in a single send. That simply will not work. The kernel buffer may not be large enough to send it all. The receiver's kernel buffer may not be large enough to receive it all. You need to pay attention to the return value of write(), which will tell you how many bytes were actually accepted by the kernel for sending. Call write() in a loop until all of the bytes have been accepted.

With that said, try something more like this:

/*Refer to documentation for questions and functionality, as well as limitations*/
/*I have given each section of code an index in the form of a comment, which you can refer to in the documentation*/
#include <arpa/inet.h>  /* htons() htonl()          */
#include <unistd.h>     /* read() write()           */
#include <stdlib.h>     /* exit()                   */
#include <string.h>     /* strlen() strcat()        */
#include <stdio.h>      /* FILE scanf() printf()    */

int write_all(int fd, const void *data, size_t data_size)
{
    char *ptr = (const char*) data;
    ssize_t written;

    while (data_size > 0)
    {
        written = write(fd, ptr, data_size);
        if (written < 0) return -1;
        ptr += written;
        data_size -= written;
    }

    return 0;
}

int main(void)
{
    /*startof[a]*/
    char filename[256];
    FILE *file_pointer;
    unsigned int file_size;
    unsigned short int port_number;
    struct sockaddr_in listening_socket_address;
    int socket_address_size;
    int listening_socketfd;
    int new_socketfd;
    struct sockaddr_in new_socket_address;
    char HTTP_REQUEST[8192];
    char HTTP_RESPONSE_HEADER[128];
    char HTTP_RESPONSE_HEADER_FMT[] = "HTTP/1.0 200 OK\r\nContent-Type: %s\r\nContent-Length: %u\r\nConnection: close\r\n\r\n";
    char file_buffer[1024];
    char media_type[] = "image/gif";
    int request_size;
 response_size;
    /*endof[a]*/
    
    /*startof[b]*/
    printf("Please enter the name of the file (text formats only) to be transmitted today, you can give a whole path, or just the name if it is in the same directory as this program :)\nFilename: ");
    scanf("%255s", filename);
    file_pointer = fopen(filename, "rb");
    if (!file_pointer) {
        // display error message...
        return -1;
    }
    fseek(file_pointer, 0L, SEEK_END);
    file_size = ftell(file_pointer);
    printf("File: %s is Size: %u Bytes\n", filename, file_size);
    rewind(file_pointer);
    printf("File: %s has been rewinded to position: 0\n\n", filename);

    // TODO: set media_type to appropriate type
    // based on what kind of file is being sent...
    /*endof[b]*/
    
    /*startof[c]*/
    printf("Enter port number: ");
    scanf("%hu", &port_number);
    
    memset(&listening_socket_address, 0, sizeof(listening_socket_address));
    listening_socket_address.sin_family = AF_INET;
    listening_socket_address.sin_port = htons(port_number);
    listening_socket_address.sin_addr.s_addr = htonl(INADDR_ANY);    
    /*endof[c]*/
    
    /*startof[d]*/
    listening_socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listening_socketfd < 0) {
        // display error message...
        return -1;
    }
    if (bind(listening_socketfd, (struct sockaddr *) &listening_socket_address, sizeof(listening_socket_address)) < 0) {
        // display error message...
        return -1;
    }
    if (listen(listening_socketfd, 1) < 0) {
        // display error message...
        return -1;
    }
    socket_address_size = sizeof(new_socket_address);
    new_socketfd = accept(listening_socketfd, (struct sockaddr *) &new_socket_address, &socket_address_size);
    if (new_socketfd < 0) {
        // display error message...
        return -1;
    }
    /*endof[d]*/
    
    /*startof[e]*/
    // TODO: read client's request per HTTP protocol...
    request_size = read(new_socketfd, HTTP_REQUEST, 8192);
    if (request_size < 0) {
        // display error message...
        return -1;
    }
    printf("\nHere is the HTTP Request:\n\n%.*s", request_size, HTTP_REQUEST);
    /*endof[e]*/
    
    /*startof[f]*/
    response_size = sprintf(HTTP_RESPONSE_HEADER, HTTP_RESPONSE_HEADER_FMT, media_type, file_size);
    printf("Here is the HTTP response:\n\n%s", HTTP_RESPONSE_HEADER);

    if (write_all(new_socketfd, HTTP_RESPONSE_HEADER, response_size) < 0) {
        return -1;
    }

    while (file_size > 0) {
        response_size = fread(file_buffer, 1, min(file_size, sizeof(file_buffer)), file_pointer);
        if (response_size < 1) break;
        if (write_all(new_socketfd, file_buffer, response_size) < 0) break;
        file_size -= response_size;
    }
    
    close(new_socketfd);
    /*endof[f]*/
    
    close(listening_socketfd);
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文