zhxy/http服务器/appweb-4.3.4-0/doc/guide/appweb/users/webSockets.html

331 lines
20 KiB
HTML
Raw Normal View History

2022-01-06 15:41:19 +00:00
<!-- BeginDsi "dsi/head.html" -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Embedthis Appweb 4.3.4 Documentation</title>
<meta name="keywords" content="embedded web server, web server software, embedded HTTP, application web server,
embedded server, small web server, HTTP server, library web server, library HTTP, HTTP library" />
<meta name="description" content="Embedthis Sofware provides commercial and open source embedded web servers for
devices and applications." />
<meta name="robots" content="index,follow" />
<link href="../../../doc.css" rel="stylesheet" type="text/css" />
<link href="../../../print.css" rel="stylesheet" type="text/css" media="print"/>
<!--[if IE]>
<link href="../../../iehacks.css" rel="stylesheet" type="text/css" />
<![endif]-->
<link href="http://www.google.com/cse/style/look/default.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div class="top">
<a class="logo" href="http://appwebserver.org/">&nbsp;</a>
<div class="topRight">
<div class="search">
<div id="cse-search-form"></div>
<div class="version">Embedthis Appweb 4.3.4</div>
</div>
</div>
<div class="crumbs">
<a href="../../../index.html">Home</a>
<!-- EndDsi -->
&gt; <a href="index.html">Users Guide</a> &gt; <b>WebSockets</b>
</div>
</div>
<div class="content">
<div class="contentRight">
<!-- BeginDsi "dsi/usersGuideSeeAlso.html" -->
<h1>See Also</h1>
<ul class="nav">
<li><a href="../../../guide/appweb/users/index.html">User Guide Overview</a></li>
<li><a href="../../../guide/appweb/users/configuration.html">Configuring Appweb</a></li>
<li><a href="../../../guide/appweb/users/ports.html">Ports and Binding</a></li>
<li><a href="../../../guide/appweb/users/lang.html">Multi-Language Support</a></li>
<li><a href="../../../guide/appweb/users/authentication.html">User Authorization</a></li>
<li><a href="../../../guide/appweb/users/logFiles.html">Log Files</a></li>
<li><a href="../../../guide/appweb/users/vhosts.html">Virtual Hosts</a></li>
<li><a href="../../../guide/appweb/users/security.html">Security Considerations</a></li>
<li><a href="../../../guide/appweb/users/ssl.html">SSL</a></li>
<li><a href="../../../guide/appweb/users/modules.html">Appweb Modules</a></li>
<li><a href="../../../guide/appweb/users/stages.html">Pipeline Stages</a></li>
<li><a href="../../../guide/appweb/users/client.html">HTTP Client</a></li>
<li><a href="../../../guide/appweb/users/webSockets.html">WebSockets</a></li>
<li><a href="../../../guide/appweb/users/frameworks.html">Web Frameworks</a></li>
<li><a href="../../../ref/appweb/architecture.html">Appweb Architecture</a></li>
</ul>
<!-- EndDsi -->
</div>
<div class="contentLeft">
<h1>WebSockets</h1>
<p><a href="http://en.wikipedia.org/wiki/WebSocket">WebSockets</a> is a technology providing
interactive communication between a server and client. It is an IETF standard defined by <a
href="http://tools.ietf.org/html/rfc6455">RFC 6455</a>.</p>
<p>Normal HTML connections follow a request/response paradigm and do not easily support asynchronous
communications or unsolicited data pushed from the server to the client. WebSockets solves this
by supporting bidirectional, full-duplex communications over persistent connections. A WebSocket
connection is established over a standard HTTP connection and is then upgraded without impacting the
original connection. This means it will work with existing networking infrastructure including firewalls and
proxies.</p>
<p>WebSockets is currently supported in the current releases of all major browsers, including:
Chrome, Firefox, IE, Opera and Safari.</p>
<h2>Appweb Implementation</h2>
<p>Appweb implements WebSockets as an optional pipeline filter called <i>WebSockFilter</i>.
The filter implements the WebSockets protocol, handshaking and provides a C language API. The
webSock filter observes the WebSockets HTTP headers and manages the connection handshaking with the
client. It also manages the framing and encoding/decoding of message data.</p>
<p>The webSock filter is configured into the pipeline using the <a href="dir/route.html#addFilter">AddFilter</a> directive.</p>
<h2>WebSocket Handshake</h2>
<p>A WebSocket connection begins life as a normal HTTP request and is upgraded to the WebSocket protocol.
The WebSocketFilter is activated by a set of WebSocket HTTP headers from the client that describes
a desired WebSocket connection. Here is a typical client HTTP request requiring a WebSocket upgrade:</p>
<pre>
GET /websock/proto/msg HTTP/1.1
Host: example.com
<b>Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Protocol: chat, better-chat
Sec-WebSocket-Key: 50cLrugr7h3yAbe5Kpc52Q==
Sec-WebSocket-Version: 13
Origin: http://example.com</b>
</pre>
<p>The WebSocket filter constructs a handshake response that includes an accepted key and selected
protocol. For example:
<pre>
HTTP/1.1 101 Switching Protocols
Server: Embedthis-http/4.1.0
Date: Sat, 06 Oct 2013 05:10:15 GMT
<b>Connection: Upgrade
Upgrade: WebSocket
Sec-WebSocket-Accept: 58ij/Yod1NTjzqcyjkZbZk6V6v0=
Sec-WebSocket-Protocol: chat</b>
X-Inactivity-Timeout: 600
X-Request-Timeout: 600
</pre>
<p>Once the handshake message has been sent, the server is free to send messages to the client.
Once the client receives the handshake, it can send messages to the server. Either side can send
at anytime thereafter. Communications are thus full-duplex.</p>
<h2>Message Types</h2>
<p>WebSockets supports several message types:</p>
<ul>
<li>Text in UTF-8</li>
<li>Binary</li>
<li>Close</li>
<li>Ping/Pong</li>
</ul>
<h3>Text Messages</h3>
<p>Text messages must be valid UTF-8 strings. The receiving peer will validate and reject non-conforming
strings. However, Appweb can be configured to accept invalid UTF-8 strings via the
<a href="dir/route.html#ignoreEncodingErrors">ignoreEncodingErrors</a> appweb directive.</p>
<h3>Binary Messages</h3>
<p>Binary message allow the transmission of any content. Messages can be an arbitrary length up to the maximum
specified by the <a href="dir/sandbox.html#limitWebSocketsMessage">LimitWebSocketsMessage</a> appweb.conf directive. Messages are broken into frames
of no more than the length specified by the <a href="dir/sandbox.html#limitWebSocketsFrame">LimitWebSocketsFrame</a> directive.
The <a href="dir/sandbox.html#limitWebSocketsPacket">LimitWebSocketsPacket</a> directive defines what is the largest packet that will be
passed on a single read to the user callback receiving incoming WebSocket messages.</p>
<h3>Close Message</h3>
<p>Ordinarily, WebSocket communications are terminated by sending a <i>Close</i> message. The close
message includes a status code and an optional <i>reason</i> string to explain why the connection is being closed. The
<i>reason</i> string must be less than 124 bytes in length so as to fit into a single WebSocket frame.</p>
<h3>Ping/Pong Messages</h3>
<p>To keep a communications channel alive, it is sometimes necessary to send regular messages to indicate
the channel is still being used. Some servers, browsers or proxies may close an
idle connection. The Ping/Pong WebSockets messages are designed to send non-application level traffic
that will prevent the channel from being prematurely closed.<p>
<p>A ping message may be sent by either side and the peer will reply with <i>pong</i>
message response. The pong message is generated internally by the WebSockets layer and is similarly
consumed by the WebSockets layer at the peer. The application layer may initiate the peer message, but
it will never see the pong response.</p>
<p>Appweb has a <a href="dir/route.html#webSocketsPing">WebSocketsPing</a> appweb.conf directive that can be used to automatically
send ping messages at a specified interval. Note: use of this directive defeats all Appweb timeouts
for an idle WebSockets connection.</p>
<h2>Timeouts</h2>
<p>The standard Appweb request and inactivity timeouts can be used for WebSocket communications.
Typically, a route will be defined in the appweb.conf file for WebSockets and it will include
appropriate request and inactivity timeout directives.
The <a href="dir/sandbox.html#requestTimeout">RequestTimeout</a> gives the total time a WebSocket connection may remain open.
The <a href="dir/sandbox.html#requestTimeout">InactivityTimeout</a> specifies the maximum time a WebSocket connection may be
completely idle. Note that ping/pong messages will reset an inactivity timeout.</p>
<h2>Configuration</h2>
<p>It is necessary to create a dedicated <a href="dir/route.html#route">Route</a> for WebSockets communications.
This will define a unique URI prefix for WebSocket communications and configure the WebSocket filter.
Any number of WebSocket routes can be defined. For example:</p>
<pre>
&lt;Route ^/websock/{controller}$&gt;
WebSocketsProtocol chat # Use the chat application protocol
AddFilter webSocketFilter # Add the WebSockets filter
AddHandler espHandler # Run an ESP controller
Source test.c # Code is in test.c
Target run $1 # Use {controller}
RequestTimeout 2hrs # Maximum connection time
InactivityTimeout 5mins # Maximum idle time
&lt;/Route&gt;
</pre>
<p>This creates a route for URIs beginning with <i>"/websock"</i> for WebSockets communications.
It uses an ESP controller to respond to incoming messages. See below for sample ESP
WebSocket code.</p>
<h2>WebSockets Directives</h2>
<p>The following directives are supported for controlling WebSocket communications within a route.</p>
<table title="directives">
<thead><tr><th>Directive</th><th>Purpose</th></tr>
<tbody>
<tr><td>IgnoreEncodingErrors</td><td>Ignore UTF-8 text message encoding errors</td></tr>
<tr><td>InactivityTimeout</td><td>Maximum idle time before closing a connection</td></tr>
<tr><td>RequestTimeout</td><td>Maximum duration before closing a connection</td></tr>
<tr><td>LimitWebSockets</td><td>Maximum number of simultaneous WebSocket sessions</td></tr>
<tr><td>LimitWebSocketsFrame</td><td>Maximum WebSockets message frame size</td></tr>
<tr><td>LimitWebSocketsMessage</td><td>Maximum WebSockets message size </td></tr>
<tr><td>LimitWebSocketsPacket</td><td>Maximum WebSockets message size passed to the
callback in one transaction.</td></tr>
<tr><td>WebSocketsProtocol</td><td>Application level protocol supported by this route</td></tr>
<tr><td>WebSocketsPing</td><td>Frequency to generate a ping message </td></tr>
</tbody>
</table>
<h2>WebSockets APIs</h2>
<p>Appweb provides a simple but powerful API for interaction with WebSockets.
<table title="API">
<thead><tr><th>Directive</th><th>Purpose</th></tr></thead>
<tbody>
<tr><td><a href="../../../api/http.html#http_8h_1a53cc0c3dcaf6e6da30c0975064d6bcbc">httpGetReadCount</a></td><td>Get the size of the next WebSockets
message to read</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1a6c1a4a4b4d9cfc2ce626bb5fd005e6ac">httpGetWebSocketCloseReason</a></td><td>Get the close reason supplied
by the peer</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1ad908e15f337a359e0f90258621d1329b">httpGetWebSocketProtocol</a></td><td> Get the selected web
socket protocol selected by the server</td></tr>
<tr><td><a href="../../../api/http.html#group___http_rx_1gad0b2d6713dd793d832e822fa9f9852ff">httpRead</a></td><td>Read a message</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1a038d5c42a1ef5bce910dc617987a222c">httpSend</a></td><td>Send a UTF-8 text message to
the web socket peer</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1ae7ef3ebbb7bbbbd701bdf84ab10cb6c1">httpSendBlock</a></td><td>Send a message of a given type to
the web socket peer</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1adb22d418a67109b699890888ca66053a">httpSendClose</a></td><td>Send a close message to the web
socket peer</td></tr>
<tr><td><a href="../../../api/http.html#group___http_conn_1ga6c39eab8e8b50e632f7e5620fce05318">httpSetConnNotifier</a></td><td>Define a connection callback notifier function</td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1a96f8cb3db541d8a1340caf0d2afbbb1f">httpSetWebSocketProtocols</a></td><td>Set the list of
application-level protocols supported by the client. This is a client-only API. </td></tr>
<tr><td><a href="../../../api/http.html#http_8h_1acb7184072bfb15ebf2c95f9ef6d0ba8c">httpWebSocketOrderlyClosed</a></td><td>Test if a close was orderly</td></tr>
</tbody>
</table>
<h2>Using WebSockets API with ESP</h2>
<p>ESP is an ideal web framework for use with WebSockets. ESP provides a very low latency connection
between a client request and execution of C functions. A dedicated ESP controller can be created
for the WebSocket that responds to the incoming WebSocket request. The controller then defines
a connection callback that is notified when incoming WebSockets messages arrive. This callback will
also be invoked for close or error events. For example:</p>
<pre>
#include "esp.h"
static void testCallback(HttpConn *conn, int event, int arg)
{
if (event == <b>HTTP_EVENT_READABLE</b>) {
/* Incoming web sockets message */
HttpPacket *packet = <b>httpGetPacket</b>(conn-&gt;readq);
printf("Message %s\n", mprGetBufStart(packet-&gt;content));
/* Send a reply message */
<b>httpSend</b>(conn, "Reply message at %s", mprGetDate(0));
/* No need to free buffer, the garbage collector will free */
} else if (event == HTTP_EVENT_APP_CLOSE) {
} else if (event == HTTP_EVENT_ERROR) {
}
}
/*
Action run when the client connects
*/
static void test() {
/* This keep the connection open */
dontAutoFinalize();
/* Define a callback for connection and I/O events */
httpSetConnNotifier(getConn(), testCallback);
}
/* One-time ESP loadable module initialization */
ESP_EXPORT int esp_controller_websock(HttpRoute *route, MprModule *module) {
espDefineAction(route, "test", test);
return 0;
}
</pre>
<h2>WebSocket References</h2>
<table title="Standards" class="width">
<thead>
<tr>
<th>Topic</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a></td>
<td>The WebSockets Protocol</td>
</tr>
<tr>
<td><a href="http://dev.w3.org/html5/websockets/">WebSocket API</a></td>
<td>The Javascript WebSockets API</td>
</tr>
<tr>
<td><a href="http://en.wikipedia.org/wiki/WebSocket">WebSockets Wikipedia</a></td>
<td>WebSockets Wikipedia</td>
</tr>
<tr>
<td><a href="http://lucumr.pocoo.org/2012/9/24/websockets-101/">WebSockets 101</a></td>
<td>WebSockets 101</td>
</tr>
<tr>
<td><a href="http://www.websocket.org/index.html">WebSocket.org</a></td>
<td>WebSockets background and demo</td>
</tr>
<tr>
<td><a href="http://html5demos.com/web-socket">WebSocket Online Demo</a></td>
<td>The WebSockets online test site</td>
</tr>
<tr>
<td><a
href="http://blog.kaazing.com/2012/05/09/inspecting-websocket-traffic-with-chrome-developer-tools/">Chrome
WebSocket Tools</a></td>
<td>Chrome browser developer tools guide</td>
</tr>
<tr>
<td><a href="http://www.rlgsc.com/blog/ruminations/websocket-rediscovered-travails.html">WebSocket Protocol</a></td>
<td>The WebSocket Protocol - Past Travails are to be avoided</td>
</tr>
<tr>
<td><a href="http://www.adobe.com/devnet/html5/articles/real-time-data-exchange-in-html5-with-websockets.html">Real-time Data Exchange</a></td>
<td>Real-time data exchange in HTML5 and WebSockets</td>
</tr>
<tr>
<td><a
href="http://www.lenholgate.com/blog/2011/07/websockets-is-a-stream-not-a-message-based-protocol.html">WebSockets Streams</a></td>
<td>WebSockets is a stream not a message based protocol....</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- BeginDsi "dsi/bottom.html" -->
<div class="bottom">
<p class="footnote">
<a href="../../../product/copyright.html" >&copy; Embedthis Software LLC, 2003-2013.
All rights reserved. Embedthis, Appweb, ESP, Ejscript and Embedthis GoAhead are trademarks of Embedthis Software LLC.</a>
</p>
</div>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load('search', '1', {language : 'en'});
google.setOnLoadCallback(function() {
var customSearchControl = new google.search.CustomSearchControl(
'000262706376373952077:1hs0lhenihk');
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
var options = new google.search.DrawOptions();
options.enableSearchboxOnly("http://appwebserver.org/search.html");
customSearchControl.draw('cse-search-form', options);
}, true);
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-179169-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>