Sockpp
Modern C++ socket library.
Install / Use
/learn @fpagliughi/SockppREADME
sockpp
Simple, modern, C++ network socket library.
sockpp is a fairly low-level C++ wrapper around the Berkeley sockets library using socket, acceptor, and connector classes that are familiar concepts from other languages.
The base socket class wraps a system socket handle and maintains its lifetime using the familiar RAII pattern. When the C++ object goes out of scope, it closes the underlying socket handle. Socket C++ objects are generally moveable but not copyable. A socket can be transferred from one scope (or thread) to another using std::move().
The library currently supports: IPv4 and IPv6 on Linux, Mac, and Windows. Other *nix and POSIX systems should work with little or no modification.
Unix-Domain Sockets are available on *nix systems that have an OS implementation for them.
Experimental support for secure sockets using either the OpenSSL or MbedTLS libraries was started with basic coverage. This will continue to be expanded in the near future.
There is also some experimental support for CAN bus programming on Linux using the SocketCAN package. This gives CAN bus adapters a network interface, with limitations dictated by the CAN message protocol.
All code in the library lives within the sockpp C++ namespace.
The 'master' branch is starting the move toward the v2.0 API, and is particularly unstable at the moment. You're advised to download the latest release for production use.
Latest News
Apologies, this library hasn't received much love from me in the last year+. The original plan was to get to a Version 2.0 with the following goals:
- Move the library to C++17
- Do a major refactor of error handling, to allow apps to use the library without exceptions and to achieve better thread safety.
- Add support for secure (TLS) sockets.
- Start some better documentation, particularly for new users.
Much of that was done a while back, except for the TLS support. The goal was to have an initial release that supported a choice between OpenSSL and another library that was not a fork of OpenSSL, to try to ensure some aspect of portability. That work stalled a while back, but is still the main focus for near-term development.
So the new strategy will be to release v2.0 with everything but the finished TLS support, and keep TLS marked as experimental - meaning that it will change and break in subsequent v2.x minor releases. Its formal release will target either v2.5 or v3.0, depending on whether any other breaking changes are required to accommodate it.
In the meantime, though, some documentation was started in the form of an mdBook, and is live here:
https://fpagliughi.github.io/sockpp/
Older News
Version 2.0 development is underway in this branch.
It moves the library to C++17, taking advantage of features first available in this version of the C++ language.
The idea of having "stateless" I/O operations introduced in PR #17, (which was never fully merged) is coming in the 2.0 API with a result<T> class. It's generic over the "success" return type with errors being represented by a std::error_code. This should help to significantly reduce platform issues for tracking and reporting errors.
Using a uniform result type removes the need for exceptions in most functions, except maybe constructors. In those cases where the function might throw, a comparable noexcept function is also provided which sets an error code parameter instead of throwing. So the library can be used without any exceptions if so desired by the application.
All functions that might fail due to a system error will return a result. That will eliminate the need for the "last error", and thus the cached last error variable in the socket class will disappear. The socket classes will then only wrap the socket handle, making them safer to share across threads in the same way a handle can be shared - typically with one thread for reading and another for writing.
Some work has also begun to incorporate Secure Sockets into a 2.x release of the library using either OpenSSL or MbedTLS libraries, or (likely), a build-time choice for one or the other. PR #17, which has been sitting dormant for a few years is being merged and updated, along with new work to do something comparable with OpenSSL. You will be able to chose one secure library or the other when building sockpp.
The 2.0 version will also move up to C++17 and CMake v3.15 or later.
Version 1.0 is released!
As breaking changes were starting to accumulate in the current development branch, the decision was made to release the API that has been fairly stable for the last few years as 1.0. This is from the latest v0.8.x line. That will make things going forward less confusing and allow us to maintain the v1.x branch.
Get Updates
To keep up with the latest announcements for this project, follow me at:
Mastodon: @fpagliughi@fosstodon.org
If you're using this library, send me a message and let me know how you're using it. I'm always curious to see where it winds up!
Documentation
Some documentation is live here:
https://fpagliughi.github.io/sockpp/
It's still in its infancy, but may be helpful.
Building your app with CMake
The library, when installed can normally be discovered with find_package(sockpp). It uses the namespace Sockpp and the library name sockpp.
A simple CMakeLists.txt file might look like this:
cmake_minimum_required(VERSION 3.15)
project(mysock VERSION 1.0.0)
find_package(sockpp REQUIRED)
add_executable(mysock mysock.cpp)
target_link_libraries(mysock Sockpp::sockpp)
Contributing
Contributions are accepted and appreciated. New and unstable work is done in the develop branch Please submit all pull requests against that branch, not master.
For more information, refer to: CONTRIBUTING.md
Building the Library
CMake is the supported build system.
Requirements:
- A conforming C++-17 compiler.
- gcc v8.0 or later (or) clang v5.0 or later.
- Visual Studio 2019, or later on Windows.
- CMake v3.15 or newer.
- Doxygen (optional) to generate API docs.
- Catch2 (optional) v2.x or v3.x to build and run unit tests.
To build with default options:
$ cd sockpp
$ cmake -Bbuild .
$ cmake --build build/
To install:
$ cmake --build build/ --target install
Build Options
The library has several build options via CMake to choose between creating a static or shared (dynamic) library - or both. It also allows you to build the example options, and if Doxygen is installed, it can be used to create documentation.
Variable | Default Value | Description ------------ | ------------- | ------------- SOCKPP_BUILD_SHARED | ON | Whether to build the shared library SOCKPP_BUILD_STATIC | OFF | Whether to build the static library SOCKPP_BUILD_DOCUMENTATION | OFF | Create and install the HTML based API documentation (requires Doxygen) SOCKPP_BUILD_EXAMPLES | OFF | Build example programs SOCKPP_BUILD_TESTS | OFF | Build the unit tests (requires Catch2) SOCKPP_WITH_UNIX_SOCKETS | ON (*nix), OFF (Win) | Include support for UNIX-domain sockets. Windows support it experimental. SOCKPP_WITH_CAN | OFF | Include SocketCAN support. (Linux only)
Set these using the '-D' switch in the CMake configuration command. For example, to build documentation and example apps:
$ cd sockpp
$ cmake -Bbuild -DSOCKPP_BUILD_DOCUMENTATION=ON -DSOCKPP_BUILD_EXAMPLES=ON .
$ cmake --build build/
TCP Sockets
TCP and other "streaming" network applications are usually set up as either servers or clients. An acceptor is used to create a TCP/streaming server. It binds an address and listens on a known port to accept incoming connections. When a connection is accepted, a new, streaming socket is created. That new socket can be handled directly or moved to a thread (or thread pool) for processing.
Conversely, to create a TCP client, a connector object is created and connected to a server at a known address (typically host and socket). When connected, the socket is a streaming one which can be used to read and write, directly.
For IPv4 the tcp_acceptor and tcp_connector classes are used to create servers and clients, respectively. These use the inet_address class to specify endpoint addresses composed of a 32-bit host address and a 16-bit port number.
TCP Server: tcp_acceptor
The tcp_acceptor is used to set up a server and listen for incoming connections.
int16_t port = 12345;
sockpp::tcp_acceptor acc(port);
if (!acc)
report_error(acc.last_error_str());
// Accept a new client connection
sockpp::tcp_socket sock = acc.accept();
The acceptor normally sits in a loop accepting new connections, and passes them off to another process, thread, or thread pool to interact with the client. In standard C++, this could look like:
while (true) {
// Accept a new client connection
sockpp::tcp_socket sock = acc.accept();
if (!sock) {
cerr << "Error accepting incoming connection: "
<< acc.last_error_str() << endl;
}
else {
// Create a thread and transfer the new stream to it.
thread thr(run_echo, std::move(sock));
thr.detach();
}
}
The hazards of a thread-per-connection design is well documented, but the same technique can be used to pass the socket into a thread pool, if one is available.
See the tcpechosvr.cpp example.
TCP Client: tcp_connector
The TCP client is somewhat simpler in that a tcp_connector object is created and connected, then can be used to read a
