Preamble
I recently completed a warmup for my first project in a Computer Science (CS) graduate school course. As I only have a cursory familiarity with the C programming language, this warm-up took me considerably longer than I had expected. The warm-up called for implementing two C program (which would later be compiled into binaries with gcc): a client and server. Below are some highlights of the lessons learned.
Note: in order to comply with my Graduate School’s Academic Integrity policy, some contents of this post are sanitized so as to prevent plagiarism.
Baby Steps
I knew coming into the course that I needed to brush up on my C programming; the last time I had worked with the language was in 2018, where I had engaged with Harvard’s CS50 course on EdX (available for free to audit). Over the Winter, I took a refresher course through Udemy in order to re-familiarize myself with the fundamentals of the programming language (disclosure: my employer has an established agreement with Udemy, allowing me free access to much of their content).
As others may expect, transitioning from a language belonging to a higher-level of abstraction (Python) to one much closer to the machine © is proving to be painful. However, I am grateful to my past-self for having done the prep work ahead of the course.
Starting Point
Our goal was to use socket programming in order to stand up an HTTP-like server in C that could be connected to by a client of our design. The client and server should be able to message each other, and the connection type should be protocol independent (IPv4 or IPv6).

I began by modeling my client and server off of some existing code linked to by the school:
I also had to read-up on socket programming, to which I found the following resources tremendously useful:
- Socket Programming in C/C++
An article which breaks down how IPv4 socket connections are established between two nodes. - IBM Knowledge Center (Socket Programming)
Provides well-commented source code examples for IPv6 client/server binaries. Really helped clarify how to make protocol-independent connections. - Oracle Socket Basics
Provided insight on protocol families as well as what particular functions were doing.
Challenges
After getting my server/client working off of the modeled starter code, I started by working through the server at length. My first challenge was getting the server to accept protocol-independent connections. Fortunately, the above resources helped. In brief: most of the IPv6 programming parameters/functions are backwards compatible, meaning it will accept a connection from either IPv4 (translating it from 127.0.0.1 to ::ffff:7f00:0001).
Then I had to keep the server alive (i.e., allow for clients to connect/disconnect repeatedly); again, the resources indicated this could be accomplished by using SO_REUSEADDR in the setsockopt() function.
Finally, I had to modify the code such that the server would echo back to the client whatever message it received from said client. This proved to be a trivial exercise in knowing how to implement recv() and send() alongwith how C handles strings as char arrays.
The client-side code, by contrast, proved to be much more of a struggle: in order for the client to be protocol independent (i.e. if the user provided an IPv4 or IPv6 address to connect to), I had to learn about the getaddrinfo() function. When invoked, it resolves the hostname to a singly-linked list of IP addresses (both IPv4 and IPv6); the client code then must iterate over the linked list in attempting to establish a socket connection. On succeeding, the code may execute similarly to the modeled example.
In order to implement this, I had to migrate from using sockaddr_in structures to addrinfo ones (as the latter data structures are what getaddrinfo() returns). Then I had to code the loop that went through the linked list in making the connections.
Tangentially, I also had to re-implement the itoa() function; The port parameter of getaddrinfo() is expected to be formatted as a string instead of an int. Unfortunately, gcc doesn’t apparently have itoa() in its standard C library. Therefore, I had to write a helper function to reformat the argument. Fun little exercise; refer to this link here on how it can be implemented.
Finally, I had to implement a method for sanitizing server responses back to the client. This required brushing up on how pointers and buffers worked.