0

I am writing a very simple webserver in c (winsock2).

I am able to return the contents of my html pages.

Currently, what I am doing is writing the contents of a file into a char* buffer and sending it using "send()"

Although when I try to read an image (jpg, bmp), I can't write the characters into a buffer a some characters are "null" (0).

How can I send a whole image file ?

Thanks.

Prakash Raman
  • 13,319
  • 27
  • 82
  • 132

3 Answers3

1

You can store null character in a char* buffer. You just have to use a counter to remember how many characters were written, instead of recomputing it by counting number of non-null characters (this can either be an integer or a pointer to the next point of insertion in the buffer).

To send a file, you'll do something like that:

int sendFile(int sock, const char* filename) {
    FILE* file = fopen(filename, "rb");
    if (file == NULL)
        return -1;

    if (fseek(file, 0, SEEK_END) != 0) {
        fclose(file);
        return -1;
    }

    off_t size = ftello(file);
    if (fseek(file, 0, SEEK_SET) != 0) {
        fclose(file);
        return -1;
    }

    if (SendBinaryFileHeaderAndSize(sock, size) < 0) {
        fclose(file);
        return -1;
    }

    char buffer[4096];
    for (;;) {
        size_t read = fread(buffer, 1, sizeof(buffer), file);
        if (read == 0) {
            int retcode = 0;
            if (ferror(file))
                retcode = -1;
            fclose(file);
            return retcode;
        }

        for (size_t sent = 0; sent < read;) {
            int ret = send(sock, buffer + sent, read - sent, 0);
            if (ret < 0) {
                fclose(file);
                return -1;
            }

            assert(ret <= read - sent);
            sent += ret;
        }
    }
}
Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
  • how do i know the size of the imagefile in c ? and once i know that can i use fgetc to fetch the contents from the image ? also, I think i got the size from fseek. but when I open the image in the browser, the browser is just an empty page. there is nothing in it. – Prakash Raman Mar 16 '11 at 15:40
  • 1
    You can use `fseek(file, O, SEEK_END)`, or some platform specific code (`lstat`, `GetFileInformationByHandle`, ...), to get the size of the file. You also need to check that you send the correct header (size, content-type, ...) to your client following the HTTP protocol (you can use another webserver to check what it does send when you try to access an binary file). – Sylvain Defresne Mar 16 '11 at 15:59
  • I seem to able to read the file. Although when I open it. I am able to download the file, but it says corrupt. Does fgetc return a signed char ? And does winsock.send allow unsigned chars to be transmitted ? – Prakash Raman Mar 16 '11 at 16:15
  • 1
    For a binary file, you should probably use `fread` to read whole block of it instead of reading it byte by byte with `fgetc` (this will be more efficient). The `send` function does not interpret the content of the buffer, it is transmitted as is, `fgetc` return a `int` (to be able to distinguish EOF from a simple character). So you have to take care when using the value as the `char` has been extended to `int` and the sign may have been propagated. – Sylvain Defresne Mar 16 '11 at 16:32
  • Thanks a lot, yes a very similar code worked for me. Basically what I am doing now, is transmitting 3096 bytes of data until all the bytes are sent. Thanks. – Prakash Raman Mar 17 '11 at 05:58
1

You need to understand how send() and fread() work. 0s in the buffer are not a problem for send or fread - they do not interpret their buffers as null-terminated strings.

0

Depending on how you load the image into your webserver, you would need to use either Winsock:TransmitPackets or Winsock:TransmitFile, also also wrapping the image in the appropriate HTTP headers

Note that these are MS specific extensions.

Also see c++ - Bitmap transfer using winsock getdibits and setdibits

Community
  • 1
  • 1
Peter M
  • 7,309
  • 3
  • 50
  • 91