Photo by ThisisEngineering RAEng

Nisse - Origins of a Server Library

Nisse Nisse is a C++ library that simplifies the creation of C++ web-based applications. It provides a framework for handling incoming requests and executing user-defined code asynchronously. To achieve this, Nisse creates managed socket connections that can be utilized by user code. It will automatically suspend the execution of user code and RE-USE the thread if the user code blocks during a read/write operation on a connection, thus offering easily accessible asynchronous functionality. ...

November 4, 2024 · 2 min · Loki Astari, (C)2024
Photo by Ben Griffiths

Socket Protocols

In the previous articles, I used a very simplistic protocol. In real-world situations, this protocol is not sufficient. A communications protocol is required to provide a more robust connection between client and server. This protocol allows us to validate that messages are sent correctly and generate appropriate responses that can also be validated. Designing a communication protocol is a nontrivial task. Rather than creating a new protocol from scratch, I would look for an existing protocol that matches your use case. ...

May 29, 2016 · 6 min · Loki Astari (C)2016
Photo by Oscar Nilsson

C++ Wrapper for Socket

The last two articles examined the “C Socket” interface provided by the OS. In this article, I wrap this functionality in a simple C++ class to provide guaranteed closing and apply a consistent exception strategy. The first step is to rewrite the client/server code with all the low-level socket code removed. This will help identify the interface that the wrapper class needs to implement. The client code becomes trivial. Create a ConnectSocket specifying the host and a port. Then, communicate with the server using the putMessage() and getMessage(). Note: I am continuing to use the trivial protocol that was defined in the last article: putMessage() writes a string to the socket then closes the connection; getMessage() reads a socket until it is closed by the other end (I will cover more sophisticated protocols in a subsequent article). ...

May 26, 2016 · 4 min · Loki Astari (C)2016
Photo by Roman Synkevych

Socket Read/Write

Checking read/write success The read() and write() commands can fail in several ways but can also succeed without reading/writing all the data. A common mistake is not checking the amount of data read/written from/to a stream. Interestingly, not all error conditions are fatal, and reading/writing can potentially be resumed after an error. Read To determine whether you have read all the information available on a stream, you need to define a communication protocol (like HTTP). The protocol for the first version of this server is very simple. Messages are passed as strings (not null-terminated), and the end of the message is marked by closing the write stream. Thus, a client can send one message and receive one reply with each connection it makes. ...

April 9, 2016 · 8 min · Loki Astari (C)2016
Photo by Ken Blode

Socket Programming in C

Building a simple client/server application is the standard first internet-based application developers attempt. These applications are built on top of the socket communication library, but socket programming in C++ is not obvious as there are no standard libraries, and thus, you have to fall back to the C API. The closest “standardish” sort of thing we have is Boost.asio, which is at the other end of the spectrum in terms of API and involves a cognitive leap to understand what is happening underneath (or you can trust the library maintainers). The other alternative is libcurl; the “easy curl” layer is an abstraction of the socket() API, while the “multi curl” layer is an abstraction of the pselect() API that allows multiple sockets to be handled in a single thread. ...

April 8, 2016 · 4 min · Loki Astari (C)2016
Photo by ThisisEngineering RAEng

Memory Resizing

So I never really considered why the resize of vector used a constant expansion of 1.5 or 2 (in some popular implementations). That was until I did my previous article series “Vector” where I concentrated a lot on resource management and did a section on resizing the vector. Initially, I tried to be clever in the code, a mistake. I used a resize value of 1.62 (an approximation of Phi) because I vaguely remembered reading an article that this was the optimum resize factor. When I put this out for code review, it was pointed out that this value was too large, the optimum value must be less than or equal to Phi (1.6180339887), and that exceeding this limit made things much worse. ...

March 25, 2016 · 3 min · Loki Astari (C)2016
Photo by Possessed Photography

Vector - The Other Stuff

So, the C++ standard specifies a set of requirements for containers. Very few requirements are specified in terms of containers, so adhering to these strictly is not required (unless you want to be considered for the standard). But they provide an insight into what can be done with them, and if you support them, it will allow your container to be more easily used with some features of the language and standard library. I am not going to go over all of them here (that is left as an exercise for the reader), but I will go over the ones I would expect to see in a simple implementation (the kind you would see in a university project). ...

March 20, 2016 · 8 min · Loki Astari, (C)2016
Photo by Matthew Brodeur

Vector - Simple Optimizations

Now that we have used std::is_nothrow_move_constructible, we can also examine a couple of other types available in the template utility library. Optimized Destruction Since we have to manually call the destructor on all objects in the container (because we are using placement new), we can look to see if we can optimize that. The type std::is_trivially_destructible detects if the type is Trivially destructible. This basically means that there will be no side effects from the destructor (See: Section 12.4 Paragraph 5 of the standard). For types we don’t need to call the destructor of the object. For the Vector class, this means we can eliminate the call to the destructor but, more importantly, the loop. ...

March 19, 2016 · 5 min · Loki Astari, (C)2016
Photo by Alex Knight

Vector - Resize

Because resizing a vector is expensive, the std::vector class uses exponential growth to minimize the number of times that the vector is resized: a technique we replicate in this version. But every now and then, you still need to resize the internal buffer. In the current version, resizing the vector requires allocating a new buffer and copying all the members into it. We use the copy and swap idiom to provide the strong exception guarantee (If an exception is thrown, all resources are cleaned up, and the object remains unchanged). ...

March 12, 2016 · 7 min · Loki Astari, (C)2016
Photo by Ben Griffiths

Vector - Resource Management Copy Swap

In the previous article, I went over basic allocation for a Vector like class. In this article, I want to put some detail around the copy assignment operator and resizing the underlying Vector. Unlike the other methods previously discussed, these methods have to deal with both construction and destruction of elements and the potential of exceptions interrupting the processes. The goal is to provide exception safe methods that provide the strong exception guarantee for the object and do not leak resources. ...

February 29, 2016 · 7 min · Loki Astari, (C)2016