• Stars
    star
    165
  • Rank 228,906 (Top 5 %)
  • Language
    C++
  • License
    MIT License
  • Created almost 5 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A single header c++ websocket client/server lib for linux

websocket

A single header c++ websocket client/server lib for linux that implements rfc6455.

Server class WSServer

As this lib uses template callback functions, user need to define 3 event handlers in his own class: onWSConnect(), onWSClose() and onWSMsg():

  // called when a new websocket connection is about to open
  // optional: origin, protocol, extensions will be nullptr if not exist in the request headers
  // optional: fill resp_protocol[resp_protocol_size] to add protocol to response headers
  // optional: fill resp_extensions[resp_extensions_size] to add extensions to response headers
  // return true if accept this new connection
  bool onWSConnect(WSConnection& conn, const char* request_uri, const char* host, const char* origin, const char* protocol,
                   const char* extensions, char* resp_protocol, uint32_t resp_protocol_size, char* resp_extensions,
                   uint32_t resp_extensions_size) {
    ...
  }
                   
  // called when a websocket connection is closed
  // status_code 1005 means no status code in the close msg
  // status_code 1006 means not a clean close(tcp connection closed without a close msg)
  void onWSClose(WSConnection& conn, uint16_t status_code, const char* reason) {
    ...
  }
  
  // onWSMsg is used if RecvSegment == false(by default), called when a whole msg is received
  void onWSMsg(WSConnection& conn, uint8_t opcode, const uint8_t* payload, uint32_t pl_len) {
    ...
  }

To get the server running, user calls init() once to start the server and poll() repetitively to trigger events defined above:

  // newconn_timeout: new tcp connection max inactive time in milliseconds, 0 means no limit
  // openconn_timeout: open ws connection max inactive time in milliseconds, 0 means no limit
  // if failed, call getLastError() for the reason
  bool init(const char* server_ip, uint16_t server_port, uint64_t newconn_timeout = 0, uint64_t openconn_timeout = 0);
  
  // non-blocking
  void poll(EventHandler* handler);

Connection class WSConnection

User can't create WSConnection objects himself, but only get WSConnection references from event handler parameters. However user is allowed to save the reference as long as the connection is not closed. WSConnection exposes below functions to use:

  // get remote network address
  bool getPeername(struct sockaddr_in& addr);
  
  // if not closed
  bool isConnected();
  
  // send a msg or a segment
  // if sending a msg of multiple segments, only set fin to true for the last one
  void send(uint8_t opcode, const uint8_t* payload, uint32_t pl_len, bool fin = true);
  
  // clean close the connection with optional status_code and reason
  // status_code 1005 means don't include status_code in close msg
  void close(uint16_t status_code = 1005, const char* reason = "");

It also allows to attach user-defined data structure to a WSConnection for user to operate on:

ConnUserData user_data;

Client class WSClient

WSClient is actually a subclass of WSConnection with one additional connect function wsConnect which is blocking:

  // timeout: connect timeout in milliseconds, 0 means no limit
  // if failed, call getLastError() for the reason
  bool wsConnect(uint64_t timeout, const char* server_ip, uint16_t server_port, const char* request_uri,
                 const char* host, const char* origin = nullptr, const char* protocol = nullptr,
                 const char* extensions = nullptr, char* resp_protocol = nullptr, uint32_t resp_protocol_size = 0,
                 char* resp_extensions = nullptr, uint32_t resp_extensions_size = 0)

And similar to WSServer, user need to define event handler function onWSClose() and onWSMsg()(but not onWSConnect()), and call the non-blocking poll() to trigger events.

Configurations and Limitations

Most of the server and client configurations are defined as class template parameters as below:

// EventHandler: user defined type defining the required event handler functions
// ConnUserData: user defined type attached to a WSConnection as member name `user_data`
// RecvSegment: switch to use segment handler function `onWSSegment` instead of `onWSMsg`
// RecvBufSize: msg/segment receive buffer size, too long msgs will cause connection being closed with status code 1009
// MaxConns: for WSServer only, max number of active connections
template<typename EventHandler, typename ConnUserData = char, bool RecvSegment = false, uint32_t RecvBufSize = 4096, uint32_t MaxConns = 10>

Note that if RecvSegment is set to true, onWSSegment() will be called in replace of onWSMsg() with 2 additional parameters:

// pl_start_idx: index in the whole msg for the 1st byte of payload
// fin: whether it's the last segment
void onWSSegment(WSConnection& conn, uint8_t opcode, const uint8_t* payload, uint32_t pl_len, uint32_t pl_start_idx, bool fin);

And if the c++ standard is older than c++17, user need to define both event handlers even if only one will be called(c++17 introduces if constexpr which allows only one function to be defined).

One implementation issue for client: client is not fully conformant to rfc6455 in that handshaking key and msg masking key are of constant values instead of random ones, for the purpose of efficiency and simplicity.

One performance consideration for server: as the library is using a simple busy-polling model instead of things like epoll, the number of active connections should be limited, as the default value of MaxConns implies.

Thread safety: this lib is not thread safe.

TLS support: this lib does not support TLS.

Examples

Example codes implement a admincmd client and server on top of websocket layer, allowing the author to add a web client and reusing all of the existing admin commands provided by the c++ server.

More Repositories

1

fmtlog

fmtlog is a performant fmtlib-style logging library with latency in nanoseconds.
C++
768
star
2

tcpshm

A connection-oriented persistent message queue framework based on TCP or SHM(shared memory)
C++
454
star
3

tscns

A low overhead nanosecond clock based on x86 TSC
C++
286
star
4

SPSC_Queue

A highly optimized single producer single consumer message queue C++ template
C++
242
star
5

pollnet

A collection of non-blocking(polling) network libs for Linux, also support solarflare APIs(Tcpdirect/Efvi)
C++
208
star
6

str

A SIMD optimized fixed-length string class along with an adaptive hash table for fast searching
C++
124
star
7

WFMPMC

A bounded wait-free(almost) zero-copy MPMC queue written in C++11, which can also reside in SHM for IPC
C++
109
star
8

TCP-UDP-Proxy

A proxy server program written in C++ that can forward TCP or UDP packets
C++
87
star
9

SPMC_Queue

A simple and efficient single producer multiple consumer queue, suititable for both ITC and IPC.
C++
76
star
10

MPSC_Queue

A multi-producer single consumer queue C++ template suitable for async logging with SHM IPC support
C++
73
star
11

PubSubQueue

An efficient single publisher multiple subscriber message queue for Linux IPC
C++
54
star
12

admincmd

A shell style command line framework which can easily be incorporated into a linux c++ server, supporting telnet/nc clients
C++
38
star
13

NanoLogLite

A revised version of NanoLog which writes human readable log file, and is easier to use.
C++
36
star
14

efvitcp

A Tcp/Ip stack implementation on top of Solarflare ef_vi, and a C++ headers only framework for tcp multiplexing client/server.
30
star
15

Algos

A collection of C++ libraries I personally maintained and used in competitive programming problems.
C++
4
star
16

SuperImageView-for-Android

A powerful Image browser for Android that supports multiple gestures
Java
1
star