Using Web Sockets
The WebSocket protocol is a TCP based methodology that exploits the HTTP 1.1 "Upgrade" header. Sloop provides support via the Sloop::Websocket module.
A fundamental purpose for WebSockets, according to RFC 6455, is
...to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g., using XMLHttpRequest or <iframe>s and long polling).
It is certainly a significant improvement on ajax long polling, and all major modern browsers implement support for it via a simple javascript API. This API is documented by W3C, although this documentation delves a bit into the implementation and there are probably easier tutorials to be found online. The centerpiece of the API is the WebSocket
class.
To demonstrate this with Sloop, we can use a simple echo server. Although there are some perl WebSocket client implementations on CPAN, the simplest way to test this is with an actual browser, so we need to serve up an actual page.
#!/usr/bin/perl use strict; use warnings FATAL => qw(all); use Sloop::Server; use Sloop::Static; use Sloop::WebSocket; my $Sloop = Sloop::Server->new(port => 8080); die if !$Sloop; $Sloop->{handlers} = { '/' => sub { # The current working directory must contain # 'index.html' and 'websocket.js'. Sloop::Static::directory ( shift, path => './', ); }, 'websocket' => sub { my $client = shift; my $check = Sloop::WebSocket::start ( $client, dataIn => sub { # Echo the data received back. my ($sender, $msgref) = (shift, shift); Sloop::WebSocket::sendFrame($sender, $msgref); } ); } }; $Sloop->run;
Note that $sender
and $client
are the same object here, but using the callback parameter and not a capture avoids a circular reference.
The index.html
page itself is pretty straightforward.
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>WebSocket Demo</title> <script type="text/javascript" src="websocket.js"></script> </head> <body> <!-- A simple form which calls a javascript function instead of submitting directly to the server. --> <form> <label>Message: </label> <input id="msgbox"> <button type="button" onclick="sendMessage()" >Send</button> </form> <!-- Somewhere to print the server's reply --> <h2 id="replytxt"></h2> </body> </html>
This needs to be in the working directory of the server, along with another key component, websocket.js
.
// Initialize the WebSocket; the complete DOM does not have to be available // so we do not have to wait for the page to load, etc. Websock = new WebSocket('ws://'+location.hostname+':'+location.port+'/websocket') if (!Websock) alert("Could not connect WebSocket!") else { // Define necessary WebSocket functions. Websock.onopen = function () { alert("WebSocket connected.") } Websock.onmessage = function (msg) { var txtbox = document.getElementById("replytxt") txtbox.innerHTML = msg.data } } // Called from the HTML form's button. function sendMessage () { if (!Websock) { alert("WebSocket not connected.") return } var mbox = document.getElementById("msgbox") if (mbox.value) Websock.send(mbox.value) mbox.value = "" }
You can download these in a package. Run sloop.pl
and connect to localhost:8080 to try the echo server.