function makeSamples(frequency, duration) { var samplespercycle = 44100 / frequency;
var samples = new Uint16Array(44100 * duration);
var da = 2 * Math.PI / samplespercycle;
for (var i = 0, a = 0; i < samples.length; i++, a += da) { samples[i] = Math.floor(Math.sin(a / 300000) * 32768);
}
var wss = new WebSocketServer({server: app, path: '/data'});
var samples = makeSamples(20000, 10);
With new technology comes a new set of problems. In the case of WebSockets, the challenges relate to compatibility with the proxy servers that mediate HTTP connections in most company networks. A firewall, proxy server, or switch always is the lynchpin of an enterprise, and these devices and servers limit the kind of traffic you’re allowed to send to and from the server.
The WebSocket protocol uses the HTTP upgrade system (which is normally used for HTTPS/SSL) to “upgrade” an HTTP connection to a WebSocket connection. Some proxy servers are not able to handle this handshake and will drop the connection. So, even if a given client uses the WebSocket protocol, it may not be possible to establish a connection.
When you use WebSocket Secure (wss://), wire traffic is encrypted and intermediate transparent proxy servers may simply allow the encrypted traffic through, so there is a much better chance that the WebSocket connection will succeed. Using encryption is not free of resource costs, but often provides the highest success rate.
Some proxy servers are harmless and work fine with WebSockets. Others will prevent WebSockets from working correctly, causing the connection to fail. In some cases, ad‐
ditional proxy server configuration may be required, and certain proxy servers may need to be upgraded to support WebSocket connections.
If unencrypted WebSocket traffic flows through an explicit or a transparent proxy server on its way to the WebSocket server, then, whether or not the proxy server behaves as it should, the connection is almost certainly bound to fail. Therefore, unencrypted Web‐
Socket connections should be used only in the simplest topologies. As WebSockets be‐
come more mainstream, proxy servers will become WebSocket aware.
If you use an encrypted WebSocket connection, then use Transport Layer Security (TLS) in the WebSocket Secure connection to ensure that an HTTP CONNECT command is issued when the browser is configured to use an explicit proxy server. This sets up a tunnel, which provides low-level end-to-end TCP communication through the HTTP proxy, between the WebSocket Secure client and the WebSocket server. In the case of trans‐
parent proxy servers, the browser is unaware of the proxy server, so no HTTP CONNECT is sent. Because the wire traffic is encrypted, however, intermediate transparent proxy servers may simply allow the encrypted traffic through, so there is a much better chance that the WebSocket connection will succeed if you use WebSocket Secure. Using en‐
cryption is not free of resource cost, but often provides the highest success rate.
A mid-2010 draft (version hixie-76) broke compatibility with reverse proxies and gateways by including 8 bytes of key data after the headers, but not advertising that data in a Content-Length: 8 header. This data was not forwarded by all intermediates, which could lead to protocol failure. More recent drafts (such as hybi-09) put the key data in a Sec-WebSocket-Key header, solving this problem.
Building your own
Things have changed since the days of fronting our servers with Apache for tasks like static resource serving. Apache configuration changes result in killing hundreds of active connections, which in turn, kills service availability.
With today’s private cloud architectures, there is a high demand for throughput and availability. If we want our services like Apache or Tomcat to come up or go down at
any time, then we simply have to put something in front of those services that can handle routing the traffic correctly, based on the cloud topology at the moment. One way to take down servers and bring up new ones without affecting service availability is to use a proxy. In most cases, HAProxy is the go to-choice for high throughput and availability.
HAProxy is a lightweight proxy server that advertises obscenely high throughput. Such companies as github, Fedora, Stack Overflow, and Twitter all use HAProxy for load balancing and scaling their infrastructure. Not only can HAProxy handle HTTP traffic, but it’s also a general-purpose TCP/IP proxy. Best of all, it’s dead simple to use.
The code that follows adds HAProxy to the previous example. The result is a reverse proxy on the WebSocket port (8081), which allows all traffic (HTTP and WS) to be sent across a common port (8080, in this case). Here is a simple reverse proxy from the example WebSocket server: timeout client 86400000 default_backend www_backend
acl is_websocket hdr(Upgrade) -i WebSocket acl is_websocket hdr_beg(Host) -i ws use_backend socket_backend if is_websocket backend www_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For timeout server 30000
timeout connect 4000
server apiserver 192.168.1.101:8080 weight 1 maxconn 4096 check backend socket_backend
balance roundrobin
option forwardfor # This sets X-Forwarded-For timeout queue 5000
timeout server 86400000 timeout connect 86400000
server apiserver 192.168.1.101:8081 weight 1 maxconn 4096 check
This approach is universal to any HTTP server that embeds a separate WebSocket server on a different port.
Frameworks
There are just about as many Comet, AJAX push-based, WebSocket frameworks and servers as there are mobile web frameworks. So sorting out which ones are built for lightweight mobile environments and which ones may be suitable only for desktop browsers is essential. Keep in mind that graceful degradation comes at a cost. If you choose a WebSocket framework that degrades in 10 different ways, you do not want your mobile clients to be penalized with a heavy framework download. To provide real-time connectivity to every browser, you need a framework that will detect the most capable transport at runtime.
You may already be familiar with projects such as Node.js, Ruby EventMachine, or Python Twisted. These projects use an event-based API to allow you to create network-aware applications in just a few lines of code. But what about enterprise-grade perfor‐
mance and concurrency? Take a look at how a few of your options stack up.
Vert.x
A fully asynchronous, general-purpose application container for JVM languages, Vert.x) takes inspiration from such event-driven frameworks as Node.js, then combines it with a distributed event bus and sticks it all on the JVM. The result is a runtime with real concurrency and unrivalled performance. Vert.x then exposes the API in Ruby, JavaScript, Groovy, and Java. Vert.x supports TCP, HTTP, WebSockets, and many more modules. You can think of it as Node.js for JVM languages.
Vert.x recommends SockJS to provide a WebSocket-like object on the client. Under the hood, SockJS tries to use native WebSockets first. If that fails, it can use a variety of browser-specific transport protocols and presents them through WebSocket-like ab‐
stractions. SockJS is intended to work for all modern browsers and in environments that don’t support WebSocket protcol, such as behind restrictive corporate proxies.
Vert.x requires JDK 1.7.0. It uses such open source projects as Netty, JRuby, Mozilla Rhino, and Hazelcast, and is under MIT and Apache 2.0 license.
The code for SockJS page set-up is:
<!DOCTYPE html>
<html>
<head>
<title>my app</title>
</head>
var sock = new SockJS('http://mydomain.com/my_prefix');
sock.onopen = function() { console.log('open');
};
sock.onmessage = function(e) { console.log('message', e.data);
Specifically built for use with a Node.js server, Socket.IO (http://socket.io) has the capa‐
bility to be used with any backend after you set fallback capabilities via Flash. Socket.IO aims to make real-time apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms. Specifically, Socket.IO sup‐
ports iOS, Android, WebOs, and WebKit License, and is under MIT license.
The page setup for Socket.IO is simple:
<!DOCTYPE html>
<html>
<head>
<title>my app</title>
</head> socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) { console.log(data);
});
});
Finally, set up your client with:
var socket = io.connect('http://localhost');
socket.on('news', function (data) { console.log(data);
socket.emit('my other event', { my: 'data' });
});
Atmosphere
Atmosphere is the only portable WebSocket/Comet framework supporting Scala, Groo‐
vy, and Java. Atmosphere (https://github.com/Atmosphere) can run on any Java-based web server, including Tomcat, Jetty, GlassFish, Weblogic, Grizzly, JBoss, Resin, and more. The Atmosphere framework has both client (JavaScript, iQuery, GWT) and server components. You can find many examples of how to use Atmosphere in your project at https://github.com/Atmosphere/atmosphere/tree/master/samples (Figure 5-1).
The main concern when using WebSockets is graceful degradation, be‐
cause most mobile browsers and servers have mixed support. All the frameworks mentioned (plus many more) support some kind of fallback when WebSockets is not available within the browser. All of these fall‐
backs, however, share the same problem: they carry the overhead of HTTP, which doesn’t make them well suited for low-latency mobile applications. Until all mobile browsers support WebSockets, this is a problem users and developers are forced to deal with.
Figure 5-1. A few of many examples listed in Atmosphere’s github repo