The first homework assignment for my distributed objects programming course was to create a chatroom server and client using C++, POSIX threads, and sockets. I have some experience with these concepts and actually programming with them from my operating systems course. My previous experience, however, was not as involved and did not have so many threads going in so many different directions. My server was started by opening a socket. Whenever a new client or connection was made, the server created a new thread. That new thread listened for a command: CREATE, LIST, DELETE, or JOIN. These commands all referenced a global map. I am not claiming that using a global variable was the proper way to do this, but security was not a focus for this assignment and I only had one week to complete it. This was the quick and dirty way that solved the problem at hand. The global variable was a map that used the chatroom’s name as a key and the value contained the chatroom’s port, a flag that showed when the room was deleted, and all the currently connected clients’ sockets’ file descriptors. That might be confusing in words, but you can check out the repo here for some more clarification. Whenever a CREATE was received, the server would create a new thread that was its own server. That new server was simply a chatroom. The rabbit hole gets deeper though because each client that entered the chatroom needed their own thread to receive their messages and send them to the other clients in the chatroom. Thinking through the amount of threads and the design of the server I faced another problem.
The biggest problem for me was using pointers again. I decided to make most of the entries for the values of a chatroom pointers because each chatroom was created and inserted into the global map on line 240 in
crsd.c but needed to be accessed by other threads later. I could not just enter variables because they could change and I would possibly need to do that while created threads were still running. For some reason I started off by using references to variables that I had created earlier. This was the reason I had trouble. If I created two chatrooms, the messages in one chatroom would go to the most recently created chatroom. The reason had to do with the ports specifically. I inserted a map entry using the chatroom’s port as a reference to the int that I used to find the next open port in the
crsd.c. Every time that I created a new chatroom, the old chatrooms also updated their ports to the new port because they all just pointed to the same variable. The fix I used for this was to use
new int(port) whenever I started creating the new map entry. This data type is still a pointer to an int but it is in a different memory address than the original
int port variable. This is a good reminder that values pointed to can be changed by anything with that memory address and references are not deep copies. Sadly it just took me an extra day to remember this. Pointers can be tricky so make sure that you know what they actually point to and what else has that address before you rely on it as a source of truth.