README.md

General

Introduction

WebSocket is a computer communications protocol, providing full-duplex and bi-directionnal communication channels over a single TCP connection. IXWebSocket is a C++ library for client and server Websocket communication, and for client HTTP communication. The code is derived from easywsclient and from the Satori C SDK. It has been tested on the following platforms.

Build

CMakefiles for the library and the examples are available. This library has few dependencies, so it is possible to just add the source files into your project. Otherwise the usual way will suffice.

mkdir build # make a build dir so that you can build out of tree.
cd build
cmake ..
make -j
make install # will install to /usr/local on Unix, on macOS it is a good idea to sudo chown -R `whoami`:staff /usr/local

Finally you can build and install the ws command line tool with Homebrew. The homebrew version might be slightly out of date.

brew tap bsergean/IXWebSocket
brew install IXWebSocket

Implementation details

Per Message Deflate compression.

The per message deflate compression option is supported. It can lead to very nice bandbwith savings (20x !) if your messages are similar, which is often the case for example for chat applications. All features of the spec should be supported.

TLS/SSL

Connections can be optionally secured and encrypted with TLS/SSL when using a wss:// endpoint, or using normal un-encrypted socket with ws:// endpoints. AppleSSL is used on iOS and macOS, and OpenSSL is used on Android and Linux.

Polling and background thread work

No manual polling to fetch data is required. Data is sent and received instantly by using a background thread for receiving data and the select system call to be notified by the OS of incoming data. No timeout is used for select so that the background thread is only woken up when data is available, to optimize battery life. This is also the recommended way of using select according to the select tutorial, section select law. Read and Writes to the socket are non blocking. Data is sent right away and not enqueued by writing directly to the socket, which is possible since system socket implementations allow concurrent read/writes. However concurrent writes need to be protected with mutex.

Automatic reconnection

If the remote end (server) breaks the connection, the code will try to perpetually reconnect, by using an exponential backoff strategy, capped at one retry every 10 seconds.

Large messages

Large frames are broken up into smaller chunks or messages to avoid filling up the os tcp buffers, which is permitted thanks to WebSocket fragmentation. Messages up to 1G were sent and received succesfully.

Limitations

No utf-8 validation is made when sending TEXT message with sendText()

Automatic reconnection works at the TCP socket level, and will detect remote end disconnects. However, if the device/computer network become unreachable (by turning off wifi), it is quite hard to reliably and timely detect it at the socket level using recv and send error codes. Here is a good discussion on the subject. This behavior is consistent with other runtimes such as node.js. One way to detect a disconnected device with low level C code is to do a name resolution with DNS but this can be expensive. Mobile devices have good and reliable API to do that.

The server code is using select to detect incoming data, and creates one OS thread per connection. This is not as scalable as strategies using epoll or kqueue.

C++ code organization

Here is a simplistic diagram which explains how the code is structured in term of class/modules.

API

Sending messages

If the connection was closed and sending failed, the return value will be set to false.

ReadyState

getReadyState() returns the state of the connection. There are 4 possible states.

ReadyState::Connecting - The connection is not yet open.

ReadyState::Open - The connection is open and ready to communicate.

ReadyState::Closing - The connection is in the process of closing.

ReadyState::Closed - The connection is closed or could not be opened.

Open and Close notifications

The onMessage event will be fired when the connection is opened or closed. This is similar to the Javascript browser API, which has open and close events notification that can be registered with the browser addEventListener.

start, stop

websocket.start() connect to the remote server and starts the message receiving background thread.

websocket.stop() disconnect from the remote server and closes the background thread.

Configuring the remote url

The url can be set and queried after a websocket object has been created. You will have to call stop and start if you want to disconnect and connect to that new url.

std::string url("wss://example.com");
websocket.configure(url);

Ping/Pong support

Ping/pong messages are used to implement keep-alive. 2 message types exists to identify ping and pong messages. Note that when a ping message is received, a pong is instantly send back as requested by the WebSocket spec.