×
Home Articles Tutorials Videos Projects
Writing a Web Server in C Like a Real Chad

Writing a Web Server in C Like a Real Chad

7 Jan, 2023

So you want to be a real chad and write your own web server in the most pure and mighty C? Well buckle up, because it's going to be a bumpy ride. But don't worry, I'll be your trusty guide as we navigate the treacherous waters of network programming and HTTP.

Let's start with the basics. A web server is essentially just a program that listens for incoming connections on a specific port, and then sends back a response when a request is made. Today we will be making a very simple web server that spits out "Hello world" in only 56 lines of C code. Nothing too fancy, but cool nonetheless.

To do this, we'll need to use a few low-level C libraries like sys/socket.h and netinet/in.h. These libraries provide the necessary functions for creating and manipulating sockets, which are the fundamental building blocks of network communication. Create a file server.c and add the following headers:

// include our libraries
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h> // for write()

Next we need the main function which is the entry point of our server:

int main() {
  printf("Running Server on localhost:4000 \n");



  return 0;
}

We print a message to indicate that our server is running. Next, we need to create a socket and bind it to a port. We can do this by utilizing the libraries we imported earlier:

  // create a socket
  int the_socket = socket(AF_INET, SOCK_STREAM, 0);
  if (the_socket < 0) {
    printf("could not create socket 😭");
    return 1;
  }

We do not want to handle errors as we are just trying to make a basic server, so we terminate the server if a socket could not be created by returning from the main function.

After creating a socket, we need to bind it to a port. This can be done as thus:

// bind the_socket to port 4000
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(4000); // port 4000
  if (bind(the_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    printf("could not bind socket 😭");
    return 1;
  }

Now that the socket has been created and bound to a port, we can listen for connections:

// listen for connections
  listen(the_socket, 10);

Great! Now we have a functioning web server that listens for incoming connections on port 4000. But it doesn't do much beyond that. Let's add some code to handle incoming requests and send back a response.

for (;;) {
    // accept connections
    int new_client = accept(the_socket, NULL, NULL);
    if (new_client < 0) {
      printf("could not accept connection 😭");
      return 1;
    }

    // connected to a client!
    printf("connected to client 🥳\n");

    // construct a response
    char *status_line = "HTTP/1.1 200 OK\r\n";
    char *headers = "Content-Type: text/html\r\n";
    char *body = "<html><body><h1>Hello, Chad!</h1></body></html>\r\n";
    int content_length = strlen(body);
    char length_str[50];
    sprintf(length_str, "Content-Length: %d\r\n", content_length);
    char response[1000];
    sprintf(response, "%s%s%s\r\n%s", status_line, headers, length_str, body);

    // send the response to the client
    write(new_client, response, strlen(response));
  }

Putting it all together

#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h> // for write()

int main() {
  printf("Running Server on localhost:4000 \n");

  // create a socket
  int the_socket = socket(AF_INET, SOCK_STREAM, 0);
  if (the_socket < 0) {
    printf("could not create socket 😭");
    return 1;
  }

  // bind the_socket to port 4000
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(4000); // port 4000
  if (bind(the_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
    printf("could not bind socket 😭");
    return 1;
  }

  // listen for connections
  listen(the_socket, 10);

  for (;;) {
    // accept connections
    int new_client = accept(the_socket, NULL, NULL);
    if (new_client < 0) {
      printf("could not accept connection 😭");
      return 1;
    }

    // connected to a client!
    printf("connected to client 🥳\n");

    // construct a response
    char *status_line = "HTTP/1.1 200 OK\r\n";
    char *headers = "Content-Type: text/html\r\n";
    char *body = "<html><body><h1>Hello, Chad!</h1></body></html>\r\n";
    int content_length = strlen(body);
    char length_str[50];
    sprintf(length_str, "Content-Length: %d\r\n", content_length);
    char response[1000];
    sprintf(response, "%s%s%s\r\n%s", status_line, headers, length_str, body);

    // send the response to the client
    write(new_client, response, strlen(response));
  }

  return 0;
}

Running the server

To compile and run the server, run the following command in the terminal:

gcc -o server server.c

This will create an executable file called server from the source code in server.c.

To run the program, you can simply type the following command:

./server

This will start the web server, which will listen for incoming connections on port 4000. You can then use a web browser or a command-line HTTP client like curl to send a request to http://localhost:4000. The server should respond with an HTML page containing the text "Hello, Chad!".

There you have it! A fully functioning web server in C that can handle incoming requests and send back a simple HTML response. But wait, there's more! As a real chad, you'll want to add some extra functionality to your web server. Here are a few ideas:

With these features, your web server will be well on its way to becoming a fully-fledged HTTP server. i am not a rickroll

Thank you for reading,

Give me a follow on Twitter to get updated on my new articles, and join my Discord server if you would like to see cool open-source projects i am building with an awesome community of software enthusiasts.

Consider donating, or becoming a sponsor to help me transition into making open-source software, full-time.

this website does not show ads, track you, or collect your data. have a great day :)