IXWebSocket/README.md

460 lines
18 KiB
Markdown
Raw Normal View History

2018-09-27 23:56:48 +02:00
# General
2019-01-08 19:13:23 +01:00
![Alt text](https://travis-ci.org/machinezone/IXWebSocket.svg?branch=master)
2018-09-27 23:56:48 +02:00
## Introduction
[*WebSocket*](https://en.wikipedia.org/wiki/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 and server HTTP communication. The code is derived from [easywsclient](https://github.com/dhbaird/easywsclient) and from the [Satori C SDK](https://github.com/satori-com/satori-rtm-sdk-c). It has been tested on the following platforms.
2018-10-09 06:50:55 +02:00
* macOS
* iOS
* Linux
* Android
* Windows
2018-09-27 23:56:48 +02:00
## Examples
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
The [*ws*](https://github.com/machinezone/IXWebSocket/tree/master/ws) folder countains many interactive programs for chat, [file transfers](https://github.com/machinezone/IXWebSocket/blob/master/ws/ws_send.cpp), [curl like](https://github.com/machinezone/IXWebSocket/blob/master/ws/ws_http_client.cpp) http clients, demonstrating client and server usage.
2018-09-27 23:56:48 +02:00
2019-01-04 03:00:48 +01:00
Here is what the client API looks like.
2018-09-27 23:56:48 +02:00
```
ix::WebSocket webSocket;
std::string url("ws://localhost:8080/");
2019-01-25 04:54:10 +01:00
webSocket.setUrl(url);
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
// Optional heart beat, sent every 45 seconds when there is not any traffic
2019-01-25 04:54:10 +01:00
// to make sure that load balancers do not kill an idle connection.
webSocket.setHeartBeatPeriod(45);
2018-09-27 23:56:48 +02:00
// Per message deflate connection is enabled by default. You can tweak its parameters or disable it
webSocket.disablePerMessageDeflate();
2018-09-27 23:56:48 +02:00
// Setup a callback to be fired when a message or an event (open, close, error) is received
webSocket.setOnMessageCallback(
2019-06-09 21:02:02 +02:00
[](const ix::WebSocketMessagePtr& msg)
2018-09-27 23:56:48 +02:00
{
2019-06-09 21:02:02 +02:00
if (msg->type == ix::WebSocketMessageType::Message)
2018-09-27 23:56:48 +02:00
{
2019-06-09 21:02:02 +02:00
std::cout << msg->str << std::endl;
2018-09-27 23:56:48 +02:00
}
});
// Now that our callback is setup, we can start our background thread and receive messages
webSocket.start();
2019-06-09 21:02:02 +02:00
// Send a message to the server (default to TEXT mode)
2018-09-27 23:56:48 +02:00
webSocket.send("hello world");
2019-06-09 21:02:02 +02:00
// The message can be sent in BINARY mode (useful if you send MsgPack data for example)
webSocket.sendBinary("some serialized binary data");
2018-09-27 23:56:48 +02:00
// ... finally ...
// Stop the connection
2018-10-05 23:35:09 +02:00
webSocket.stop()
2018-09-27 23:56:48 +02:00
```
2019-01-04 03:00:48 +01:00
Here is what the server API looks like. Note that server support is very recent and subject to changes.
```
// Run a server on localhost at a given port.
// Bound host name, max connections and listen backlog can also be passed in as parameters.
ix::WebSocketServer server(port);
server.setOnConnectionCallback(
[&server](std::shared_ptr<WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
2019-01-04 03:00:48 +01:00
{
webSocket->setOnMessageCallback(
2019-06-09 21:02:02 +02:00
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr msg)
2019-01-04 03:00:48 +01:00
{
2019-06-09 21:02:02 +02:00
if (msg->type == ix::WebSocketMessageType::Open)
2019-01-04 03:00:48 +01:00
{
std::cerr << "New connection" << std::endl;
2019-03-11 00:07:48 +01:00
// A connection state object is available, and has a default id
// You can subclass ConnectionState and pass an alternate factory
// to override it. It is useful if you want to store custom
// attributes per connection (authenticated bool flag, attributes, etc...)
std::cerr << "id: " << connectionState->getId() << std::endl;
2019-03-11 00:07:48 +01:00
// The uri the client did connect to.
2019-06-09 21:02:02 +02:00
std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
2019-03-11 00:07:48 +01:00
2019-01-04 03:00:48 +01:00
std::cerr << "Headers:" << std::endl;
2019-06-09 21:02:02 +02:00
for (auto it : msg->openInfo.headers)
2019-01-04 03:00:48 +01:00
{
std::cerr << it.first << ": " << it.second << std::endl;
}
}
2019-06-09 21:02:02 +02:00
else if (msg->type == ix::WebSocketMessageType::Message)
2019-01-04 03:00:48 +01:00
{
2019-01-15 18:36:43 +01:00
// For an echo server, we just send back to the client whatever was received by the server
2019-01-04 03:00:48 +01:00
// All connected clients are available in an std::set. See the broadcast cpp example.
2019-06-09 21:02:02 +02:00
// Second parameter tells whether we are sending the message in binary or text mode.
// Here we send it in the same mode as it was received.
webSocket->send(msg->str, msg->binary);
2019-01-04 03:00:48 +01:00
}
}
);
}
);
auto res = server.listen();
if (!res.first)
{
// Error handling
return 1;
}
// Run the server in the background. Server can be stoped by calling server.stop()
server.start();
// Block until server.stop() is called.
server.wait();
```
Here is what the HTTP client API looks like.
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
```
//
// Preparation
//
HttpClient httpClient;
HttpRequestArgsPtr args = httpClient.createRequest();
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
// Custom headers can be set
WebSocketHttpHeaders headers;
headers["Foo"] = "bar";
args->extraHeaders = headers;
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
// Timeout options
args->connectTimeout = connectTimeout;
args->transferTimeout = transferTimeout;
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
// Redirect options
args->followRedirects = followRedirects;
args->maxRedirects = maxRedirects;
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
// Misc
args->compress = compress; // Enable gzip compression
args->verbose = verbose;
args->logger = [](const std::string& msg)
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
{
std::cout << msg;
};
//
// Synchronous Request
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
//
HttpResponsePtr out;
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
std::string url = "https://www.google.com";
// HEAD request
out = httpClient.head(url, args);
// GET request
out = httpClient.get(url, args);
// POST request with parameters
HttpParameters httpParameters;
httpParameters["foo"] = "bar";
out = httpClient.post(url, httpParameters, args);
// POST request with a body
out = httpClient.post(url, std::string("foo=bar"), args);
//
// Result
//
auto errorCode = response->errorCode; // Can be HttpErrorCode::Ok, HttpErrorCode::UrlMalformed, etc...
auto errorCode = response->errorCode; // 200, 404, etc...
auto responseHeaders = response->headers; // All the headers in a special case-insensitive unordered_map of (string, string)
auto payload = response->payload; // All the bytes from the response as an std::string
auto errorMsg = response->errorMsg; // Descriptive error message in case of failure
auto uploadSize = response->uploadSize; // Byte count of uploaded data
auto downloadSize = response->downloadSize; // Byte count of downloaded data
//
// Asynchronous Request
//
bool async = true;
HttpClient httpClient(async);
auto args = httpClient.createRequest(url, HttpClient::kGet);
// Push the request to a queue,
bool ok = httpClient.performRequest(args, [](const HttpResponsePtr& response)
{
// This callback execute in a background thread. Make sure you uses appropriate protection such as mutex
auto statusCode = response->statusCode; // acess results
}
);
// ok will be false if your httpClient is not async
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
```
Here is what the HTTP server API looks like. Note that HTTP server support is very, very recent and subject to changes.
```
ix::HttpServer server(port, hostname);
auto res = server.listen();
if (!res.first)
{
std::cerr << res.second << std::endl;
return 1;
}
server.start();
server.wait();
```
If you want to handle how requests are processed, implement the setOnConnectionCallback callback, which takes an HttpRequestPtr as input, and returns an HttpResponsePtr. You can look at HttpServer::setDefaultConnectionCallback for a slightly more advanced callback example.
```
setOnConnectionCallback(
[this](HttpRequestPtr request,
std::shared_ptr<ConnectionState> /*connectionState*/) -> HttpResponsePtr
{
// Build a string for the response
std::stringstream ss;
ss << request->method
<< " "
<< request->uri;
std::string content = ss.str();
return std::make_shared<HttpResponse>(200, "OK",
HttpErrorCode::Ok,
WebSocketHttpHeaders(),
content);
}
```
2018-10-09 00:23:01 +02:00
## 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
```
Headers and a static library will be installed to the target dir.
2018-10-09 00:23:01 +02:00
A [conan](https://conan.io/) file is available at [conan-IXWebSocket](https://github.com/Zinnion/conan-IXWebSocket).
There is a unittest which can be executed by typing `make test`.
There is a Dockerfile for running some code on Linux. To use docker-compose you must make a docker container first.
```
$ make docker
...
$ docker compose up &
...
$ docker exec -it ixwebsocket_ws_1 bash
app@ca2340eb9106:~$ ws --help
ws is a websocket tool
...
```
2019-01-04 03:00:48 +01:00
Finally you can build and install the `ws command line tool` with Homebrew. The homebrew version might be slightly out of date.
```
2019-03-18 23:45:33 +01:00
brew tap bsergean/IXWebSocket
brew install IXWebSocket
```
2018-09-27 23:56:48 +02:00
## 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.
2018-09-27 23:56:48 +02:00
### 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, OpenSSL is used on Android and Linux, mbedTLS is used on Windows.
2018-09-27 23:56:48 +02:00
### 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](http://man7.org/linux/man-pages/man2/select.2.html) 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](https://linux.die.net/man/2/select_tut). 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](https://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid) 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. This behavior can be disabled.
2018-09-27 23:56:48 +02:00
### Large messages
2019-03-25 05:48:14 +01:00
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](https://tools.ietf.org/html/rfc6455#section-5.4). Messages up to 1G were sent and received succesfully.
2018-09-27 23:56:48 +02:00
## Limitations
* On Windows TLS is not setup yet to validate certificates.
* There is no convenient way to embed a ca cert.
2019-03-25 05:48:14 +01:00
* No utf-8 validation is made when sending TEXT message with sendText()
2018-09-27 23:56:48 +02:00
* 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](https://stackoverflow.com/questions/14782143/linux-socket-how-to-detect-disconnected-network-in-a-client-program) 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.
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
* 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.
2018-09-27 23:56:48 +02:00
## C++ code organization
Feature/http (#16) * add skeleton and broken http client code. GET returns "Resource temporarily unavailable" errors... * linux compile fix * can GET some pages * Update formatting in README.md * unittest for sending large messages * document bug * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces * Update README.md Add note about message fragmentation. * Feature/ws cli (#15) * New command line tool for transfering files / still very beta. * add readme * use cli11 for argument parsing * json -> msgpack * stop using base64 and use binary which can be stored in message pack * add target for building with homebrew * all CMakeLists are referenced by the top level one * add ws_chat and ws_connect sub commands to ws * cleanup * add echo and broadcast server as ws sub-commands * add gitignore * comments * ping pong added to ws * mv cobra_publisher under ws folder * Update README.md * linux build fix * linux build fix * move http_client to a ws sub-command * simple HTTP post support (urlencode parameters) * can specify extra headers * chunk encoding / simple redirect support / -I option * follow redirects is optional * make README vim markdown plugin friendly * cleanup argument parsing + add socket creation factory * add missing file * http gzip compression * cleanup * doc * Feature/send large message (#14) * introduce send fragment * can pass a fin frame * can send messages which are a perfect multiple of the chunk size * set fin only for last fragment * cleanup * last fragment should be of type CONTINUATION * Add simple send and receive programs * speedups receiving + better way to wait for thing * receive speedup by using linked list of chunks instead of large array * document bug * use chunks to receive data * trailing spaces
2019-03-01 06:54:03 +01:00
Here is a simplistic diagram which explains how the code is structured in term of class/modules.
2018-09-27 23:56:48 +02:00
```
2019-01-04 03:00:48 +01:00
+-----------------------+ --- Public
2018-09-27 23:56:48 +02:00
| | Start the receiving Background thread. Auto reconnection. Simple websocket Ping.
| IXWebSocket | Interface used by C++ test clients. No IX dependencies.
| |
2018-09-27 23:56:48 +02:00
+-----------------------+
| |
2019-01-04 03:00:48 +01:00
| IXWebSocketServer | Run a server and give each connections its own WebSocket object.
| | Each connection is handled in a new OS thread.
| |
+-----------------------+ --- Private
2019-01-04 03:00:48 +01:00
| |
2018-09-27 23:56:48 +02:00
| IXWebSocketTransport | Low level websocket code, framing, managing raw socket. Adapted from easywsclient.
| |
+-----------------------+
| |
2019-01-04 03:00:48 +01:00
| IXWebSocketHandshake | Establish the connection between client and server.
| |
+-----------------------+
| |
2018-09-27 23:56:48 +02:00
| IXWebSocket | ws:// Unencrypted Socket handler
| IXWebSocketAppleSSL | wss:// TLS encrypted Socket AppleSSL handler. Used on iOS and macOS
| IXWebSocketOpenSSL | wss:// TLS encrypted Socket OpenSSL handler. Used on Android and Linux
| | Can be used on macOS too.
+-----------------------+
2019-01-04 03:00:48 +01:00
| |
| IXSocketConnect | Connect to the remote host (client).
| |
+-----------------------+
| |
| IXDNSLookup | Does DNS resolution asynchronously so that it can be interrupted.
| |
+-----------------------+
2018-09-27 23:56:48 +02:00
```
2018-10-08 00:47:38 +02:00
## API
2018-09-27 23:56:48 +02:00
### Sending messages
2018-09-28 00:34:18 +02:00
`websocket.send("foo")` will send a message.
2018-09-27 23:56:48 +02:00
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.
1. ReadyState::Connecting - The connection is not yet open.
2. ReadyState::Open - The connection is open and ready to communicate.
3. ReadyState::Closing - The connection is in the process of closing.
4. ReadyState::Closed - The connection is closed or could not be opened.
2018-09-27 23:56:48 +02:00
### 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](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), which has `open` and `close` events notification that can be registered with the browser `addEventListener`.
```
webSocket.setOnMessageCallback(
2019-06-09 21:02:02 +02:00
[](const ix::WebSocketMessagePtr& msg)
2018-09-27 23:56:48 +02:00
{
2019-06-09 21:02:02 +02:00
if (msg->type == ix::WebSocketMessageType::Open)
2018-09-27 23:56:48 +02:00
{
2018-10-27 20:46:11 +02:00
std::cout << "send greetings" << std::endl;
// Headers can be inspected (pairs of string/string)
std::cout << "Handshake Headers:" << std::endl;
2019-06-09 21:02:02 +02:00
for (auto it : msg->headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
2018-09-27 23:56:48 +02:00
}
2019-06-09 21:02:02 +02:00
else if (msg->type == ix::WebSocketMessageType::Close)
2018-09-27 23:56:48 +02:00
{
2018-10-27 20:46:11 +02:00
std::cout << "disconnected" << std::endl;
// The server can send an explicit code and reason for closing.
// This data can be accessed through the closeInfo object.
2019-06-09 21:02:02 +02:00
std::cout << msg->closeInfo.code << std::endl;
std::cout << msg->closeInfo.reason << std::endl;
2018-09-27 23:56:48 +02:00
}
}
);
```
### Error notification
A message will be fired when there is an error with the connection. The message type will be `ix::WebSocketMessageType::Error`. Multiple fields will be available on the event to describe the error.
2018-09-27 23:56:48 +02:00
```
webSocket.setOnMessageCallback(
2019-06-09 21:02:02 +02:00
[](const ix::WebSocketMessagePtr& msg)
2018-09-27 23:56:48 +02:00
{
2019-06-09 21:02:02 +02:00
if (msg->type == ix::WebSocketMessageType::Error)
2018-09-27 23:56:48 +02:00
{
std::stringstream ss;
2019-06-09 21:02:02 +02:00
ss << "Error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->eventInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->eventInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->eventInfo.http_status << std::endl;
std::cout << ss.str() << std::endl;
2018-09-27 23:56:48 +02:00
}
}
);
```
### start, stop
1. `websocket.start()` connect to the remote server and starts the message receiving background thread.
2. `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.
```
2018-09-28 00:43:31 +02:00
std::string url("wss://example.com");
2018-09-27 23:56:48 +02:00
websocket.configure(url);
```
2018-10-26 00:14:31 +02:00
### 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.
```
webSocket.setOnMessageCallback(
2019-06-09 21:02:02 +02:00
[](const ix::WebSocketMessagePtr& msg)
2018-10-26 00:14:31 +02:00
{
2019-06-09 21:02:02 +02:00
if (msg->type == ix::WebSocketMessageType::Ping ||
msg->type == ix::WebSocketMessageType::Pong)
2018-10-26 00:14:31 +02:00
{
2019-06-09 21:02:02 +02:00
std::cout << "pong data: " << msg->str << std::endl;
2018-10-26 00:14:31 +02:00
}
}
);
```
A ping message can be sent to the server, with an optional data string.
```
websocket.ping("ping data, optional (empty string is ok): limited to 125 bytes long");
2019-02-06 08:04:45 +01:00
```
2019-01-26 01:11:39 +01:00
### Heartbeat.
You can configure an optional heart beat / keep-alive, sent every 45 seconds
2019-03-18 00:08:28 +01:00
when there is no any traffic to make sure that load balancers do not kill an
2019-01-26 01:11:39 +01:00
idle connection.
```
webSocket.setHeartBeatPeriod(45);
2018-10-26 00:14:31 +02:00
```