0

Preface: I am just engaging C, so forgive my incompetence. The cause of this problem is probably basic.

Problem: I am trying to read a file and serve it over http with a socket. For some reason, the printf output of a previously read file varies depending on how much of the subsequent code is included.

Here is my code.

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include <netinet/in.h>


int main()
{

    // open a file to serve
    FILE *file;
    file = fopen("index.html", "r");
    if (file == NULL)
    {
        printf("Failed to open file.");
        exit(EXIT_FAILURE);
    }

    // Get file content
    char file_content[1024];
    if (fgets(file_content, 1024, file) != NULL)
    {

        fclose(file);

        // Add header to file content
        char http_header[2048] = "HTTP/1.1 200 OK\r\n\n";    
        strncat(http_header, file_content, 1028);

        // This output varies depending on inclusion of proceeding code.
        printf("%s", http_header);

        // create a socket
        int server_socket;
        server_socket = socket(AF_INET, SOCK_STREAM, 0);        

        // define the address
        struct sockaddr_in server_address;
        server_address.sin_family = AF_INET;
        server_address.sin_port = htons(8001);
        server_address.sin_addr.s_addr = INADDR_ANY;

        bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));        
        listen(server_socket, 1);

        int client_socket;        
        while (1)
        {
            client_socket = accept(server_socket, NULL, NULL);
            send(client_socket, http_header, sizeof(http_header), 0);
            close(client_socket);
        }
        return 0;
    }

}

If I comment out everything past the printf statement, I get this intended output..

HTTP/1.1 200 OK

<html><body>Hi</body></html>

But if I run all the code, I get this instead..

HTTP/1.1 200 OK

If I can improve my question at all, please let me know how. Thank you.

Dylan Landry
  • 860
  • 7
  • 20
  • 3
    O/T move `fclose(file);` and `return 0;` to outside of the `if(fgets(..))` check. Those things should happen whether `fgets` returns NULL or not. – yano Jan 05 '18 at 00:14
  • 3
    I suspect your file content does not include a trailing `\n` character, and your program does not terminate because of the infinite loop, so the output buffer never gets flushed. Either exit the infinite loop, or add a trailing newline character to your output. – Mark Benningfield Jan 05 '18 at 00:25
  • 1
    ... or try an `fflush(stdout);` after the `printf`. `printf` is line-buffered, `fflush(stdout);` will manually flush `stdout`. – yano Jan 05 '18 at 00:28
  • Your string `"HTTP/1.1 200 OK\r\n\n"` should be `"HTTP/1.1 200 OK\r\n\r\n"` -- every line needs to end with `\r\n`. However, that is unlikely to be your immediate problem. – Jonathan Leffler Jan 05 '18 at 00:52
  • The header should be generated before the loop; the content of the file should be echoed inside the loop. The listen/accept code is oddly placed; shouldn't that be outside the loop and you only send the file when a connection is received? – Jonathan Leffler Jan 05 '18 at 00:55

1 Answers1

1

Mark Benningfield and Yano helped me understand the problem, thanks so much to both of you.

When you execute printf(), instead of the string going directly into the terminal window, each line goes into a buffer.

Each line in the buffer must be flushed for them to show in the terminal. The buffer can be automatically flushed by these events

Strings ending in \n are automatically flushed, this is why the first line HTTP/1.1 200 OK \r\n\n displays fine. The second line <html><body>hi</body></html> does not end with a \n, or trigger any other automatic flush events, so it does not display.

Usually this is not a problem because when the program terminates, the buffer is automatically flushed, and all lines that entered the buffer through printf show up in the terminal. Since my program at the bottom enters an infinite while loop, the program never terminates, and the buffer is never flushed.

Calling fflush(stdout) after printf forces a write of stdout's entire buffer.

More info on fflush

Dylan Landry
  • 860
  • 7
  • 20
  • Note that the line buffering settings may vary amongst implementations, you are just describing how yours works by default – M.M Jan 05 '18 at 01:17
  • 2
    "Strings ending in \n are automatically flushed" --> Not quite. It depends on [What are the rules of automatic flushing stdout buffer in C?](https://stackoverflow.com/q/39536212/2410359) – chux - Reinstate Monica Jan 05 '18 at 01:39