Skip to content

Instantly share code, notes, and snippets.

@martinsik
Created September 6, 2012 10:03
Show Gist options
  • Save martinsik/3654228 to your computer and use it in GitHub Desktop.
Save martinsik/3654228 to your computer and use it in GitHub Desktop.
Simple WebSocket server based on libwebsockets. For full description read http://martinsikora.com/libwebsockets-simple-websocket-server
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
window.WebSocket = window.WebSocket || window.MozWebSocket;
var websocket = new WebSocket('ws://127.0.0.1:9000',
'dumb-increment-protocol');
websocket.onopen = function () {
$('h1').css('color', 'green');
};
websocket.onerror = function () {
$('h1').css('color', 'red');
};
websocket.onmessage = function (message) {
console.log(message.data);
$('div').append($('<p>', { text: message.data }));
};
$('button').click(function(e) {
e.preventDefault();
websocket.send($('input').val());
$('input').val('');
});
});
</script>
</head>
<body>
<h1>WebSockets test</h1>
<form>
<input type="text" />
<button>Send</button>
</form>
<div></div>
</body>
</html>
#include <stdio.h>
#include <stdlib.h>
#include <libwebsockets.h>
static int callback_http(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
return 0;
}
static int callback_dumb_increment(struct libwebsocket_context * this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting
printf("connection established\n");
break;
case LWS_CALLBACK_RECEIVE: { // the funny part
// create a buffer to hold our response
// it has to have some pre and post padding. You don't need to care
// what comes there, libwebsockets will do everything for you. For more info see
// http://git.warmcat.com/cgi-bin/cgit/libwebsockets/tree/lib/libwebsockets.h#n597
unsigned char *buf = (unsigned char*) malloc(LWS_SEND_BUFFER_PRE_PADDING + len +
LWS_SEND_BUFFER_POST_PADDING);
int i;
// pointer to `void *in` holds the incomming request
// we're just going to put it in reverse order and put it in `buf` with
// correct offset. `len` holds length of the request.
for (i=0; i < len; i++) {
buf[LWS_SEND_BUFFER_PRE_PADDING + (len - 1) - i ] = ((char *) in)[i];
}
// log what we recieved and what we're going to send as a response.
// that disco syntax `%.*s` is used to print just a part of our buffer
// http://stackoverflow.com/questions/5189071/print-part-of-char-array
printf("received data: %s, replying: %.*s\n", (char *) in, (int) len,
buf + LWS_SEND_BUFFER_PRE_PADDING);
// send response
// just notice that we have to tell where exactly our response starts. That's
// why there's `buf[LWS_SEND_BUFFER_PRE_PADDING]` and how long it is.
// we know that our response has the same length as request because
// it's the same message in reverse order.
libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], len, LWS_WRITE_TEXT);
// release memory back into the wild
free(buf);
break;
}
default:
break;
}
return 0;
}
static struct libwebsocket_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"http-only", // name
callback_http, // callback
0 // per_session_data_size
},
{
"dumb-increment-protocol", // protocol name - very important!
callback_dumb_increment, // callback
0 // we don't use any per session data
},
{
NULL, NULL, 0 /* End of list */
}
};
int main(void) {
// server url will be http://localhost:9000
int port = 9000;
const char *interface = NULL;
struct libwebsocket_context *context;
// we're not using ssl
const char *cert_path = NULL;
const char *key_path = NULL;
// no special options
int opts = 0;
// create libwebsocket context representing this server
context = libwebsocket_create_context(port, interface, protocols,
libwebsocket_internal_extensions,
cert_path, key_path, -1, -1, opts);
if (context == NULL) {
fprintf(stderr, "libwebsocket init failed\n");
return -1;
}
printf("starting server...\n");
// infinite loop, to end this server send SIGTERM. (CTRL+C)
while (1) {
libwebsocket_service(context, 50);
// libwebsocket_service will process all waiting events with their
// callback functions and then wait 50 ms.
// (this is a single threaded webserver and this will keep our server
// from generating load while there are not requests to process)
}
libwebsocket_context_destroy(context);
return 0;
}
@jimbo72
Copy link

jimbo72 commented May 23, 2014

Sorry for this stupid question, but how to compile ?
link http://martinsikora.com/libwebsockets-compiling-libraries-and-projects is down

@bjardnin
Copy link

There seems to be a change in the libwebsockets api, in case of interest, you can check my fork where the code is adjusted to new api
https://gist.github.com/bjardnin/1df8cc5eb43ce5008f7e#file-libwebsockets-websocket-c

@linuxdeveloper
Copy link

How to change C source file for using my own IP address instead of localhost?

@rragu
Copy link

rragu commented Apr 22, 2016

Hi,

We are using CentOS release 6.7 (Final) version. Can someone please provide the steps to build libwebsocket server (C++). It would be more helpful for us and the response is more appreciated.
Git Path : https://github.com/warmcat/libwebsockets

Regards,
Ragu R

@mAPBhlJ
Copy link

mAPBhlJ commented Jul 12, 2016

@zYeoman
Copy link

zYeoman commented Feb 16, 2017

There was a change in the libwebsockets api. New API: libwebsocket_* -> lws_*, and callback function without this.

You can check My fork, which works under version 2.1.0.

@joeywu321
Copy link

joeywu321 commented Jun 20, 2017

@#zYeoman
Why i use your change.
But i test it by https://www.websocket.org/echo.html
I still can't run in LWS_CALLBACK_ESTABLISHED?
Only LWS_CALLBACK_PROTOCOL_INIT reson in callback_dumb_increment(...).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment