Repository: mnisjk/cppWebSockets
Branch: master
Commit: fbd2358d77f9
Files: 15
Total size: 31.2 KB
Directory structure:
gitextract_agtrf0tl/
├── LICENSE
├── README.md
├── Util.cpp
├── Util.h
├── WebSocketServer.cpp
├── WebSocketServer.h
└── examples/
├── chatServer/
│ ├── Makefile
│ ├── chatServer.cpp
│ └── index.html
├── echoServer/
│ ├── Makefile
│ ├── echoServer.cpp
│ └── index.html
└── multiPollServer/
├── Makefile
├── index.html
└── multiPollServer.cpp
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
Copyright (c) 2014, Jason Kruse <jason@jasonkruse.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* The names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL JASON KRUSE BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*********************************
Please note this is a C++ wrapper around Andy Green's libwebsockets C library.
libwebsockets is licensed under the MIT license.
================================================
FILE: README.md
================================================
cppWebSockets
===========
A simple, lightweight c++ WebSockets server library wrapped around the popular libwebsockets c library.
### Usage
Create a class that extends `WebSocketServer` and implement the following callbacks
```
void onConnect( int socketID ); // New websocket connection
void onMessage( int socketID, const string& data ); // Message received from connected client
void onDisconnect( int socketID ); // Client disconnect
void onError( int socketID, const string& message ); // Networking error
```
Then simply instantiate your server and call `run()`
```
MyServer s = MyServer( 8080 ); // MyServer extends WebSocketServer listening on port 8080
s.run( );
```
At any arbitrary time, you can push a message to a client by calling `send( int socketID, string data )`.
If your server is more complex and needs to monitor its own connections in addition to WebSocket connections, you can manage your own event loop. Instead of calling `s.run( )`, use the `s.wait( )` function. A good illustration of this is located in [examples/multiPollServer/multiPollServer.cpp](https://github.com/mnisjk/cppWebSockets/blob/master/examples/multiPollServer/multiPollServer.cpp)
### Features
* Implement your own web socket server in less than 50 lines of c++.
* OpenSSL support
* WebSocket RFC6455 implementation
* Abstracts away all c pointers and managing when sockets are writable
* Push data to any client at any time
* Key => Value storage for any socket with `setValue( int socketID, const string& name, const string& value );` and `getValue( int socketID, const string& name );`
### Examples
Check out the [examples](https://github.com/mnisjk/cppWebSockets/blob/master/examples/) directory for fully implemented illustrations. There is a basic echo and chat server as well as a more complex server that manages multiple `poll( )` loops. They should demonstrate how easy this library is to use and serve as basic scaffolding for your projects.
### Dependencies
This is built on top of [warmcat](http://warmcat.com/)'s wonderful, lightweight [libwebsocket](http://libwebsockets.org/) c library. To install:
```
mnisjk@localdev ~ $ git clone git://git.libwebsockets.org/libwebsockets
mnisjk@localdev ~ $ cd libwebsockets
mnisjk@localdev libwebsockets $ cmake .
mnisjk@localdev libwebsockets $ make
mnisjk@localdev libwebsockets $ sudo make install
```
### Compile and run
All examples have Makefiles, so simply run `make` and then run the example. When creating your own projects, your compile commands will look like the following:
```
mnisjk@localdev ~ $ g++ -w -DLOG_TO_STDOUT=1 -omyserver Util.cpp WebSocketServer.cpp myserver.cpp -lwebsockets
mnisjk@localdev ~ $ ./myserver
```
================================================
FILE: Util.cpp
================================================
/** --------------------------------------------------------------------------
* Util.cpp
*
* A few very basic utility functions for WebSocketServer
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
#include <stdio.h>
#include "Util.h"
using namespace std;
#define LOG_PREFIX "[cppWebSockets] "
void Util::log( const string& message )
{
const string& logMessage = LOG_PREFIX + message;
syslog( LOG_WARNING, "%s", logMessage.c_str( ) );
#ifdef LOG_TO_STDOUT
printf( "%s\n", logMessage.c_str( ) );
#endif
}
void Util::log( const char* message )
{
log( string( message ) );
}
================================================
FILE: Util.h
================================================
/** --------------------------------------------------------------------------
* Util.h
*
* A few very basic utility functions for WebSocketServer
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
#ifndef _UTIL_H
#define _UTIL_H
#include <string>
#include <syslog.h>
#include <iostream>
#include <sstream>
using namespace std;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/// Util
/// ---------
class Util
{
public:
static void log( const string& message );
static void log( const char* message );
template<typename T>
static inline string toString(T t) { stringstream s; s << t; return s.str(); }
};
// Util.h
#endif
================================================
FILE: WebSocketServer.cpp
================================================
/** --------------------------------------------------------------------------
* WebSocketServer.cpp
*
* Base class that WebSocket implementations must inherit from. Handles the
* client connections and calls the child class callbacks for connection
* events like onConnect, onMessage, and onDisconnect.
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
#include <stdlib.h>
#include <string>
#include <cstring>
#include <sys/time.h>
#include <fcntl.h>
#include "libwebsockets.h"
#include "Util.h"
#include "WebSocketServer.h"
using namespace std;
// 0 for unlimited
#define MAX_BUFFER_SIZE 0
// Nasty hack because certain callbacks are statically defined
WebSocketServer *self;
static int callback_main( struct lws *wsi,
enum lws_callback_reasons reason,
void *user,
void *in,
size_t len )
{
int fd;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
switch( reason ) {
case LWS_CALLBACK_ESTABLISHED:
self->onConnectWrapper( lws_get_socket_fd( wsi ) );
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
fd = lws_get_socket_fd( wsi );
while( !self->connections[fd]->buffer.empty( ) )
{
const char * message = self->connections[fd]->buffer.front( );
int msgLen = strlen(message);
int charsSent = lws_write( wsi, (unsigned char *)message, msgLen, LWS_WRITE_TEXT );
if( charsSent < msgLen )
self->onErrorWrapper( fd, string( "Error writing to socket" ) );
else
// Only pop the message if it was sent successfully.
self->connections[fd]->buffer.pop_front( );
}
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_RECEIVE:
self->onMessage( lws_get_socket_fd( wsi ), string( (const char *)in, len ) );
break;
case LWS_CALLBACK_CLOSED:
self->onDisconnectWrapper( lws_get_socket_fd( wsi ) );
break;
default:
break;
}
return 0;
}
static struct lws_protocols protocols[] = {
{
"/",
callback_main,
0, // user data struct not used
MAX_BUFFER_SIZE,
},{ NULL, NULL, 0, 0 } // terminator
};
WebSocketServer::WebSocketServer( int port, const string certPath, const string& keyPath )
{
this->_port = port;
this->_certPath = certPath;
this->_keyPath = keyPath;
lws_set_log_level( 0, lwsl_emit_syslog ); // We'll do our own logging, thank you.
struct lws_context_creation_info info;
memset( &info, 0, sizeof info );
info.port = this->_port;
info.iface = NULL;
info.protocols = protocols;
#ifndef LWS_NO_EXTENSIONS
info.extensions = lws_get_internal_extensions( );
#endif
if( !this->_certPath.empty( ) && !this->_keyPath.empty( ) )
{
Util::log( "Using SSL certPath=" + this->_certPath + ". keyPath=" + this->_keyPath + "." );
info.ssl_cert_filepath = this->_certPath.c_str( );
info.ssl_private_key_filepath = this->_keyPath.c_str( );
}
else
{
Util::log( "Not using SSL" );
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
}
info.gid = -1;
info.uid = -1;
info.options = 0;
// keep alive
info.ka_time = 60; // 60 seconds until connection is suspicious
info.ka_probes = 10; // 10 probes after ^ time
info.ka_interval = 10; // 10s interval for sending probes
this->_context = lws_create_context( &info );
if( !this->_context )
throw "libwebsocket init failed";
Util::log( "Server started on port " + Util::toString( this->_port ) );
// Some of the libwebsocket stuff is define statically outside the class. This
// allows us to call instance variables from the outside. Unfortunately this
// means some attributes must be public that otherwise would be private.
self = this;
}
WebSocketServer::~WebSocketServer( )
{
// Free up some memory
for( map<int,Connection*>::const_iterator it = this->connections.begin( ); it != this->connections.end( ); ++it )
{
Connection* c = it->second;
this->connections.erase( it->first );
delete c;
}
}
void WebSocketServer::onConnectWrapper( int socketID )
{
Connection* c = new Connection;
c->createTime = time( 0 );
this->connections[ socketID ] = c;
this->onConnect( socketID );
}
void WebSocketServer::onDisconnectWrapper( int socketID )
{
this->onDisconnect( socketID );
this->_removeConnection( socketID );
}
void WebSocketServer::onErrorWrapper( int socketID, const string& message )
{
Util::log( "Error: " + message + " on socketID '" + Util::toString( socketID ) + "'" );
this->onError( socketID, message );
this->_removeConnection( socketID );
}
void WebSocketServer::send( int socketID, string data )
{
// Push this onto the buffer. It will be written out when the socket is writable.
this->connections[socketID]->buffer.push_back( data.c_str() );
}
void WebSocketServer::broadcast(string data )
{
for( map<int,Connection*>::const_iterator it = this->connections.begin( ); it != this->connections.end( ); ++it )
this->send( it->first, data );
}
void WebSocketServer::setValue( int socketID, const string& name, const string& value )
{
this->connections[socketID]->keyValueMap[name] = value;
}
string WebSocketServer::getValue( int socketID, const string& name )
{
return this->connections[socketID]->keyValueMap[name];
}
int WebSocketServer::getNumberOfConnections( )
{
return this->connections.size( );
}
void WebSocketServer::run( uint64_t timeout )
{
while( 1 )
{
this->wait( timeout );
}
}
void WebSocketServer::wait( uint64_t timeout )
{
if( lws_service( this->_context, timeout ) < 0 )
throw "Error polling for socket activity.";
}
void WebSocketServer::_removeConnection( int socketID )
{
Connection* c = this->connections[ socketID ];
this->connections.erase( socketID );
delete c;
}
================================================
FILE: WebSocketServer.h
================================================
/** --------------------------------------------------------------------------
* WebSocketServer.h
*
* Base class that WebSocket implementations must inherit from. Handles the
* client connections and calls the child class callbacks for connection
* events like onConnect, onMessage, and onDisconnect.
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
#ifndef _WEBSOCKETSERVER_H
#define _WEBSOCKETSERVER_H
#include <stdint.h>
#include <map>
#include <string>
#include <list>
#include <stdio.h>
#include <ctime>
#include <sys/time.h>
#include <iostream>
#include <sstream>
#include "libwebsockets.h"
using namespace std;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/// WebSocketServer
/// ---------
class WebSocketServer
{
public:
// Represents a client connection
struct Connection
{
list<const char*> buffer; // Ordered list of pending messages to flush out when socket is writable
map<string,string> keyValueMap;
time_t createTime;
};
// Manages connections. Unfortunately this is public because static callback for
// libwebsockets is defined outside the instance and needs access to it.
map<int,Connection*> connections;
// Constructor / Destructor
WebSocketServer( int port, const string certPath = "", const string& keyPath = "" );
~WebSocketServer( );
void run( uint64_t timeout = 50 );
void wait( uint64_t timeout = 50 );
void send( int socketID, string data );
void broadcast( string data );
// Key => value storage for each connection
string getValue( int socketID, const string& name );
void setValue( int socketID, const string& name, const string& value );
int getNumberOfConnections( );
// Overridden by children
virtual void onConnect( int socketID ) = 0;
virtual void onMessage( int socketID, const string& data ) = 0;
virtual void onDisconnect( int socketID ) = 0;
virtual void onError( int socketID, const string& message ) = 0;
// Wrappers, so we can take care of some maintenance
void onConnectWrapper( int socketID );
void onDisconnectWrapper( int socketID );
void onErrorWrapper( int socketID, const string& message );
protected:
// Nothing, yet.
private:
int _port;
string _keyPath;
string _certPath;
struct lws_context *_context;
void _removeConnection( int socketID );
};
// WebSocketServer.h
#endif
================================================
FILE: examples/chatServer/Makefile
================================================
hellomake:
g++ -w -DLOG_TO_STDOUT=1 -ochatserver ../../Util.cpp ../../WebSocketServer.cpp chatServer.cpp -lwebsockets
================================================
FILE: examples/chatServer/chatServer.cpp
================================================
/** --------------------------------------------------------------------------
* chatServer.cpp
*
* A basic example of how to implement a WebSocketServer. Creats a WS server
* bound to port 8080 for basic chatting. It listens for connections and
* assigns them a random handle based on their socket FD. Whenever a message
* is received on the server, it is sent out to all connected clients.
* received, it echos the same message back to the client.
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
// Log to stdout for easy debugging.
#define LOG_TO_STDOUT 1
#include "../../Util.h"
#include "../../WebSocketServer.h"
using namespace std;
// For any real project this should be defined separately in a header file
class ChatServer : public WebSocketServer
{
public:
ChatServer( int port );
~ChatServer( );
virtual void onConnect( int socketID );
virtual void onMessage( int socketID, const string& data );
virtual void onDisconnect( int socketID );
virtual void onError( int socketID, const string& message );
};
int main( int argc, char **argv )
{
ChatServer cs = ChatServer( 8080 );
cs.run( );
}
ChatServer::ChatServer( int port ) : WebSocketServer( port )
{
}
ChatServer::~ChatServer( )
{
}
void ChatServer::onConnect( int socketID )
{
// Give this connection a random user ID
const string& handle = "User #" + Util::toString( socketID );
Util::log( "New connection: " + handle );
// Associate this handle with the connection
this->setValue( socketID, "handle", handle );
// Let everyone know the new user has connected
this->broadcast( handle + " has connected." );
}
void ChatServer::onMessage( int socketID, const string& data )
{
// Send the received message to all connected clients in the form of 'User XX: message...'
Util::log( "Received: " + data );
const string& message = this->getValue( socketID, "handle" ) + ": " + data;
this->broadcast( message );
}
void ChatServer::onDisconnect( int socketID )
{
const string& handle = this->getValue( socketID, "handle" );
Util::log( "Disconnected: " + handle );
// Let everyone know the user has disconnected
const string& message = handle + " has disconnected.";
for( map<int,Connection*>::const_iterator it = this->connections.begin( ); it != this->connections.end( ); ++it )
if( it->first != socketID )
// The disconnected connection gets deleted after this function runs, so don't try to send to it
// (It's still around in case the implementing class wants to perform any clean up actions)
this->send( it->first, message );
}
void ChatServer::onError( int socketID, const string& message )
{
Util::log( "Error: " + message );
}
================================================
FILE: examples/chatServer/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>cppWebSockets chat server example</title>
<meta name="author" value="jason@jasonkruse.com" />
<meta name="licsense" value="BSD" />
<meta name="robots" value="none" />
<style type="text/css">
* { margin: 5px; }
textarea {
display: block;
width: 80%;
margin: 0;
height: 200px;
}
</style>
</head>
<body>
<h3>Basic chat server</h3>
<div>
<p>
This is a super basic example of a chat server using lwebsockets++. This also
shows how to use the key => value storage to associate data with a connection.
</p>
<ul><br />
<li>Compile and run the server in examples/chatServer.</li>
<li>Open this page in multiple tabs.</li>
<li>Start chatting with yourself</li>
</ul>
<p><br />
<i>Note: </i>
There is no flash fallback, so make sure you have a modern browser with
WebSocket support.
</p>
</div>
<fieldset>
<legend>Demo</legend>
<textarea id="output" readonly></textarea>
<textarea id="input" placeholder="Enter a message"></textarea>
<input type="button" name="inpuBtn" id="inputBtn" value="Send" />
<div><u>Server responses</u></div>
</fieldset>
<script type="text/javascript">
// Putting the js here after the dom is available in the browser because not using a framework
var PORT = 8080;
var ws = new WebSocket("ws://localhost:" + PORT );
var input = document.getElementById("input");
var inputBtn = document.getElementById("inputBtn");
var output = document.getElementById("output");
inputBtn.onclick = function( evt ){
sendMessage();
};
input.onkeypress = function( evt ){
var code = evt.keyCode ? evt.keyCode : evt.which;
if( code == 13 ){
evt.preventDefault();
sendMessage();
}
};
ws.onmessage = function( evt ){
addMessage( evt.data );
};
ws.onerror = function( evt ) {
addMessage( 'WebSocket error :(' );
};
ws.onopen = function( evt ) {
// Unused
};
ws.onclose = function( evt ) {
addMessage( 'You disconnected' );
};
function sendMessage( ){
ws.send(input.value);
input.value = '';
}
function addMessage( msg ){
output.value += msg + "\n";
output.scrollTop = output.scrollHeight;
}
</script>
</body>
</html>
================================================
FILE: examples/echoServer/Makefile
================================================
hellomake:
g++ -w -DLOG_TO_STDOUT=1 -oechoserver ../../Util.cpp ../../WebSocketServer.cpp echoServer.cpp -lwebsockets
================================================
FILE: examples/echoServer/echoServer.cpp
================================================
/** --------------------------------------------------------------------------
* echoServer.cpp
*
* A basic example of how to implement a WebSocketServer. Creats a WS server
* bound to port 8080. It listens for connections, and when a message is
* received, it echos the same message back to the client.
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
// Log to stdout for easy debugging.
#define LOG_TO_STDOUT 1
#include "../../Util.h"
#include "../../WebSocketServer.h"
using namespace std;
// For any real project this should be defined separately in a header file
class EchoServer : public WebSocketServer
{
public:
EchoServer( int port );
~EchoServer( );
virtual void onConnect( int socketID );
virtual void onMessage( int socketID, const string& data );
virtual void onDisconnect( int socketID );
virtual void onError( int socketID, const string& message );
};
int main( int argc, char **argv )
{
EchoServer es = EchoServer( 8080 );
es.run( );
}
EchoServer::EchoServer( int port ) : WebSocketServer( port )
{
}
EchoServer::~EchoServer( )
{
}
void EchoServer::onConnect( int socketID )
{
Util::log( "New connection" );
}
void EchoServer::onMessage( int socketID, const string& data )
{
// Reply back with the same message
Util::log( "Received: " + data );
this->send( socketID, data );
}
void EchoServer::onDisconnect( int socketID )
{
Util::log( "Disconnect" );
}
void EchoServer::onError( int socketID, const string& message )
{
Util::log( "Error: " + message );
}
================================================
FILE: examples/echoServer/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>cppWebSockets echo example</title>
<meta name="author" value="jason@jasonkruse.com" />
<meta name="licsense" value="BSD" />
<meta name="robots" value="none" />
<style type="text/css">
* { margin: 5px; }
</style>
</head>
<body>
<h3>Send a message to the server</h3>
<div>
<p>This is a super basic example of how to connect to the websocket server.</p>
<ul><br />
<li>Compile and run the server in examples/echoServer.</li>
<li>
Enter a message in the text box below; it will be sent to the server which
will reply back with the same message.
</li>
</ul>
<p><br />
<i>Note: </i>
There is no flash fallback, so make sure you have a modern browser with
WebSocket support.
</p>
</div>
<fieldset>
<legend>Demo</legend>
<input type="text" name="input" id="input" />
<input type="button" name="inpuBtn" id="inputBtn" value="Send" />
<div><u>Server responses</u></div>
<div id="output"></div>
</fieldset>
<script type="text/javascript">
// Putting the js here after the dom is available in the browser because not using a framework
var PORT = 8080;
var ws = new WebSocket("ws://localhost:" + PORT );
var input = document.getElementById("input");
var inputBtn = document.getElementById("inputBtn");
var output = document.getElementById("output");
inputBtn.onclick = function( evt ){
sendMessage();
};
input.onkeypress = function( evt ){
var code = evt.keyCode ? evt.keyCode : evt.which;
if( code == 13 )
sendMessage();
};
ws.onmessage = function( evt ){
addMessage( evt.data );
};
ws.onerror = function( evt ) {
addMessage( '<i>WebSocket error :(</i>' );
};
ws.onopen = function( evt ) {
addMessage( '<i>Connected</i>' );
};
ws.onclose = function( evt ) {
addMessage( '<i>Disconnected</i>' );
};
function sendMessage( ){
ws.send(input.value);
input.value = '';
}
function addMessage( msg ){
output.innerHTML += msg + '<br />';
}
</script>
</body>
</html>
================================================
FILE: examples/multiPollServer/Makefile
================================================
hellomake:
g++ -w -omultipollserver ../../Util.cpp ../../WebSocketServer.cpp multiPollServer.cpp -lwebsockets
================================================
FILE: examples/multiPollServer/index.html
================================================
<!DOCTYPE html>
<html>
<head>
<title>cppWebSockets multipoll example</title>
<meta name="author" value="jason@jasonkruse.com" />
<meta name="licsense" value="BSD" />
<meta name="robots" value="none" />
<style type="text/css">
* { margin: 5px; }
</style>
</head>
<body>
<h3>Multi Poll server</h3>
<div>
<p>
A basic example of how to implement a WebSocketServer <i>and</i> listen to other
fds.
</p><br />
<p>
This is useful when your server needs to handle connections from
WebSocket clients and other TCP connections at the same time.
</p>
<ul><br />
<li>Compile and run the server in examples/multiPollServer.</li>
<li>
Enter messages into standard input and they will be sent out to
all connected clients.
</li>
</ul>
<p><br />
<i>Note: </i>
There is no flash fallback, so make sure you have a modern browser with
WebSocket support.
</p>
</div>
<fieldset>
<legend>Demo</legend>
<div><u>Server messages</u></div>
<div id="output"></div>
</fieldset>
<script type="text/javascript">
// Putting the js here after the dom is available in the browser because not using a framework
var PORT = 8080;
var ws = new WebSocket("ws://localhost:" + PORT );
var output = document.getElementById("output");
ws.onmessage = function( evt ){
addMessage( evt.data );
};
ws.onerror = function( evt ) {
addMessage( '<i>WebSocket error :(</i>' );
};
ws.onopen = function( evt ) {
addMessage( '<i>Connected</i>' );
};
ws.onclose = function( evt ) {
addMessage( '<i>Disconnected</i>' );
};
function addMessage( msg ){
output.innerHTML += msg + '<br />';
}
</script>
</body>
</html>
================================================
FILE: examples/multiPollServer/multiPollServer.cpp
================================================
/** --------------------------------------------------------------------------
* multiPollServer.cpp
*
* A basic example of how to implement a WebSocketServer *AND* listen to other
* fds. This is useful when your server needs to handle connections from
* WebSocket clients and other TCP connections at the same time.
*
* It also demonstrates how to send to an arbitrary WebSocket connection at
* any time.
*
* This program listens for input on stdin and WebSockets on port 8080
* simultaneously. When new data is available on stdin (line buffered),
* it sends that string out to all connected WebSocket clients.
*
* Author : Jason Kruse <jason@jasonkruse.com> or @mnisjk
* Copyright : 2014
* License : BSD (see LICENSE)
* --------------------------------------------------------------------------
**/
#include <string>
#include <fcntl.h>
#include "../../Util.h"
#include "../../WebSocketServer.h"
#define TIMEOUT 50
#define PROMPT "message> "
using namespace std;
// For any real project this should be defined separately in a header file
class MultiPollServer : public WebSocketServer
{
public:
MultiPollServer( int port );
~MultiPollServer( );
virtual void onConnect( int socketID );
virtual void onMessage( int socketID, const string& data );
virtual void onDisconnect( int socketID );
virtual void onError( int socketID, const string& message );
};
void showPrompt( )
{
cout << PROMPT;
fflush( stdout );
}
int main( int argc, char **argv )
{
// Set up the stdin polling
int p;
char buf[1024];
struct pollfd pfds[1];
pfds[0].fd = 0;
pfds[0].events = POLLIN;
// Start the WebSocket server
MultiPollServer s = MultiPollServer( 8080 );
cout << "Type a message followed by enter to send to all connected clients." << endl << endl;
showPrompt( );
while( 1 )
{
// Handle websocket stuff
s.wait( TIMEOUT );
// Handle stdin
p = poll( pfds, 1, TIMEOUT );
if( p > 0 && pfds[0].revents & POLLIN )
{
int len = read( 0, buf, 1024 );
if( !len )
return 0;
buf[len] = 0; // make sure the c-string terminator is where we want it to be since this buf is re-used.
string input = string( buf );
input.resize( input.size( ) - 1 ); // Remove the trailing \n
// Send it out to WS clients.
Util::log( "Sending '" + input + "' to " + Util::toString( s.getNumberOfConnections( ) ) + " client(s)." );
s.broadcast( input );
// Diplay the prompt.
showPrompt( );
}
}
}
MultiPollServer::MultiPollServer( int port ) : WebSocketServer( port )
{
}
MultiPollServer::~MultiPollServer( )
{
}
void MultiPollServer::onConnect( int socketID )
{
Util::log( "New connection" );
}
void MultiPollServer::onMessage( int socketID, const string& data )
{
// Should never get hit.
}
void MultiPollServer::onDisconnect( int socketID )
{
Util::log( "Disconnect" );
}
void MultiPollServer::onError( int socketID, const string& message )
{
Util::log( "Error: " + message );
}
gitextract_agtrf0tl/
├── LICENSE
├── README.md
├── Util.cpp
├── Util.h
├── WebSocketServer.cpp
├── WebSocketServer.h
└── examples/
├── chatServer/
│ ├── Makefile
│ ├── chatServer.cpp
│ └── index.html
├── echoServer/
│ ├── Makefile
│ ├── echoServer.cpp
│ └── index.html
└── multiPollServer/
├── Makefile
├── index.html
└── multiPollServer.cpp
SYMBOL INDEX (13 symbols across 6 files) FILE: Util.h function class (line 27) | class Util FILE: WebSocketServer.cpp function callback_main (line 31) | static int callback_main( struct lws *wsi, type lws_protocols (line 77) | struct lws_protocols type lws_context_creation_info (line 93) | struct lws_context_creation_info function string (line 182) | string WebSocketServer::getValue( int socketID, const string& name ) FILE: WebSocketServer.h function class (line 33) | class WebSocketServer FILE: examples/chatServer/chatServer.cpp class ChatServer (line 25) | class ChatServer : public WebSocketServer function main (line 36) | int main( int argc, char **argv ) FILE: examples/echoServer/echoServer.cpp class EchoServer (line 23) | class EchoServer : public WebSocketServer function main (line 34) | int main( int argc, char **argv ) FILE: examples/multiPollServer/multiPollServer.cpp class MultiPollServer (line 32) | class MultiPollServer : public WebSocketServer function showPrompt (line 44) | void showPrompt( ) function main (line 50) | int main( int argc, char **argv )
Condensed preview — 15 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (34K chars).
[
{
"path": "LICENSE",
"chars": 1631,
"preview": "Copyright (c) 2014, Jason Kruse <jason@jasonkruse.com>\nAll rights reserved.\n\nRedistribution and use in source and binary"
},
{
"path": "README.md",
"chars": 2769,
"preview": "cppWebSockets\n===========\n\nA simple, lightweight c++ WebSockets server library wrapped around the popular libwebsockets "
},
{
"path": "Util.cpp",
"chars": 766,
"preview": "/** --------------------------------------------------------------------------\n * Util.cpp\n *\n * A few very basic util"
},
{
"path": "Util.h",
"chars": 916,
"preview": "/** --------------------------------------------------------------------------\n * Util.h\n *\n * A few very basic utilit"
},
{
"path": "WebSocketServer.cpp",
"chars": 6516,
"preview": "/** --------------------------------------------------------------------------\n * WebSocketServer.cpp\n *\n * Base class"
},
{
"path": "WebSocketServer.h",
"chars": 2845,
"preview": "/** --------------------------------------------------------------------------\n * WebSocketServer.h\n *\n * Base class t"
},
{
"path": "examples/chatServer/Makefile",
"chars": 119,
"preview": "hellomake:\n\tg++ -w -DLOG_TO_STDOUT=1 -ochatserver ../../Util.cpp ../../WebSocketServer.cpp chatServer.cpp -lwebsockets\n"
},
{
"path": "examples/chatServer/chatServer.cpp",
"chars": 2991,
"preview": "/** --------------------------------------------------------------------------\n * chatServer.cpp\n *\n * A basic example"
},
{
"path": "examples/chatServer/index.html",
"chars": 3076,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <title>cppWebSockets chat server example</title>\n <meta name=\"author\" "
},
{
"path": "examples/echoServer/Makefile",
"chars": 119,
"preview": "hellomake:\n\tg++ -w -DLOG_TO_STDOUT=1 -oechoserver ../../Util.cpp ../../WebSocketServer.cpp echoServer.cpp -lwebsockets\n"
},
{
"path": "examples/echoServer/echoServer.cpp",
"chars": 1772,
"preview": "/** --------------------------------------------------------------------------\n * echoServer.cpp\n *\n * A basic example"
},
{
"path": "examples/echoServer/index.html",
"chars": 2749,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <title>cppWebSockets echo example</title>\n <meta name=\"author\" value"
},
{
"path": "examples/multiPollServer/Makefile",
"chars": 111,
"preview": "hellomake:\n\tg++ -w -omultipollserver ../../Util.cpp ../../WebSocketServer.cpp multiPollServer.cpp -lwebsockets\n"
},
{
"path": "examples/multiPollServer/index.html",
"chars": 2296,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <title>cppWebSockets multipoll example</title>\n <meta name=\"author\" "
},
{
"path": "examples/multiPollServer/multiPollServer.cpp",
"chars": 3282,
"preview": "/** --------------------------------------------------------------------------\n * multiPollServer.cpp\n *\n * A basic ex"
}
]
About this extraction
This page contains the full source code of the mnisjk/cppWebSockets GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 15 files (31.2 KB), approximately 7.7k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.