Set theme jekyll-theme-cayman and migrate Page Generator content
This commit is contained in:
parent
3f8539970d
commit
9b3b2c58af
8
_config.yml
Normal file
8
_config.yml
Normal file
@ -0,0 +1,8 @@
|
||||
title: websocket-sharp
|
||||
description: A C# implementation of the WebSocket protocol client and server
|
||||
google_analytics: UA-9752433-2
|
||||
show_downloads: true
|
||||
theme: jekyll-theme-cayman
|
||||
|
||||
gems:
|
||||
- jekyll-mentions
|
691
index.html
691
index.html
@ -1,691 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>websocket-sharp by sta</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
|
||||
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/github-light.css" media="screen">
|
||||
</head>
|
||||
<body>
|
||||
<section class="page-header">
|
||||
<h1 class="project-name">websocket-sharp</h1>
|
||||
<h2 class="project-tagline">A C# implementation of the WebSocket protocol client and server</h2>
|
||||
<a href="https://github.com/sta/websocket-sharp" class="btn">View on GitHub</a>
|
||||
<a href="https://github.com/sta/websocket-sharp/zipball/master" class="btn">Download .zip</a>
|
||||
<a href="https://github.com/sta/websocket-sharp/tarball/master" class="btn">Download .tar.gz</a>
|
||||
</section>
|
||||
|
||||
<section class="main-content">
|
||||
<h2>
|
||||
<a id="welcome-to-websocket-sharp" class="anchor" href="#welcome-to-websocket-sharp" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Welcome to websocket-sharp!</h2>
|
||||
|
||||
<p><strong>websocket-sharp</strong> supports:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="#supported-websocket-specifications">RFC 6455</a></strong></li>
|
||||
<li>
|
||||
<strong><a href="#websocket-client">WebSocket Client</a></strong> and <strong><a href="#websocket-server">Server</a></strong>
|
||||
</li>
|
||||
<li>
|
||||
<strong><a href="#per-message-compression">Per-message Compression</a></strong> extension</li>
|
||||
<li><strong><a href="#secure-connection">Secure Connection</a></strong></li>
|
||||
<li><strong><a href="#http-authentication">HTTP Authentication</a></strong></li>
|
||||
<li><strong><a href="#query-string-origin-header-and-cookies">Query String, Origin header and Cookies</a></strong></li>
|
||||
<li><strong><a href="#connecting-through-the-http-proxy-server">Connecting through the HTTP Proxy server</a></strong></li>
|
||||
<li>.NET Framework <strong>3.5</strong> or later (includes compatible environment such as <strong><a href="http://www.mono-project.com">Mono</a></strong>)</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
<a id="build" class="anchor" href="#build" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Build</h2>
|
||||
|
||||
<p>websocket-sharp is built as a single assembly, <strong>websocket-sharp.dll</strong>.</p>
|
||||
|
||||
<p>websocket-sharp is developed with <strong><a href="http://monodevelop.com">MonoDevelop</a></strong>. So a simple way to build is to open <strong>websocket-sharp.sln</strong> and run build for <strong>websocket-sharp project</strong> with any of the build configurations (e.g. <code>Debug</code>) in MonoDevelop.</p>
|
||||
|
||||
<h2>
|
||||
<a id="install" class="anchor" href="#install" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Install</h2>
|
||||
|
||||
<h3>
|
||||
<a id="self-build" class="anchor" href="#self-build" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Self Build</h3>
|
||||
|
||||
<p>You should add your <strong>websocket-sharp.dll</strong> (e.g. <code>/path/to/websocket-sharp/bin/Debug/websocket-sharp.dll</code>) to the library references of your project.</p>
|
||||
|
||||
<p>If you would like to use that dll in your <strong><a href="http://unity3d.com">Unity</a></strong> project, you should add it to any folder of your project (e.g. <code>Assets/Plugins</code>) in <strong>Unity Editor</strong>.</p>
|
||||
|
||||
<h3>
|
||||
<a id="nuget-gallery" class="anchor" href="#nuget-gallery" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>NuGet Gallery</h3>
|
||||
|
||||
<p>websocket-sharp is available on the <strong><a href="http://www.nuget.org">NuGet Gallery</a></strong>, as still a <strong>prerelease</strong> version.</p>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="http://www.nuget.org/packages/WebSocketSharp">NuGet Gallery: websocket-sharp</a></strong></li>
|
||||
</ul>
|
||||
|
||||
<p>You can add websocket-sharp to your project with the <strong>NuGet Package Manager</strong>, by using the following command in the <strong>Package Manager Console</strong>.</p>
|
||||
|
||||
<pre><code>PM> Install-Package WebSocketSharp -Pre
|
||||
</code></pre>
|
||||
|
||||
<h3>
|
||||
<a id="unity-asset-store" class="anchor" href="#unity-asset-store" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Unity Asset Store</h3>
|
||||
|
||||
<p>websocket-sharp is available on the <strong>Unity Asset Store</strong>.</p>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="http://u3d.as/content/sta-blockhead/websocket-sharp-for-unity">WebSocket-Sharp for Unity</a></strong></li>
|
||||
</ul>
|
||||
|
||||
<p>It works with <strong>Unity Free</strong>, but there are some limitations:</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<strong><a href="http://docs.unity3d.com/Manual/SecuritySandbox.html">Security Sandbox of the Webplayer</a></strong> (The server isn't available in Web Player)</li>
|
||||
<li>
|
||||
<strong><a href="http://docs.unity3d.com/Manual/webgl-networking.html">WebGL Networking</a></strong> (Not available in WebGL)</li>
|
||||
<li>
|
||||
<strong>Incompatible platform</strong> (Not available for such UWP)</li>
|
||||
<li>
|
||||
<strong>Limited support for the System.IO.Compression</strong> (The compression extension isn't available on Windows)</li>
|
||||
<li>
|
||||
<strong>.NET Socket Support for iOS/Android</strong> (It requires iOS/Android Pro if your Unity is earlier than Unity 5)</li>
|
||||
<li><strong>.NET API 2.0 compatibility level for iOS/Android</strong></li>
|
||||
</ul>
|
||||
|
||||
<p><strong>.NET API 2.0 compatibility level for iOS/Android</strong> may require to fix lack of some features for later than .NET 2.0, such as the <code>System.Func<...></code> delegates (so i have added them in that asset package).</p>
|
||||
|
||||
<p>And it's priced at <strong>US$15</strong>. I think your $15 makes this project more better and accelerated, <strong>Thank you!</strong></p>
|
||||
|
||||
<h2>
|
||||
<a id="usage" class="anchor" href="#usage" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Usage</h2>
|
||||
|
||||
<h3>
|
||||
<a id="websocket-client" class="anchor" href="#websocket-client" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket Client</h3>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> System<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp<span class="pl-k">;</span>
|
||||
|
||||
<span class="pl-k">namespace</span> <span class="pl-en">Example</span>
|
||||
{
|
||||
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Program</span>
|
||||
{
|
||||
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">void</span> <span class="pl-en">Main</span> (<span class="pl-k">string[]</span> <span class="pl-smi">args</span>)
|
||||
{
|
||||
<span class="pl-k">using</span> (<span class="pl-k">var</span> ws = <span class="pl-k">new</span> WebSocket (<span class="pl-s"><span class="pl-pds">"</span>ws://dragonsnest.far/Laputa<span class="pl-pds">"</span></span>)) {
|
||||
ws.OnMessage += (sender, e) =>
|
||||
Console.WriteLine (<span class="pl-s"><span class="pl-pds">"</span>Laputa says: <span class="pl-pds">"</span></span> + e.Data);
|
||||
|
||||
ws.Connect ();
|
||||
ws.Send (<span class="pl-s"><span class="pl-pds">"</span>BALUS<span class="pl-pds">"</span></span>);
|
||||
Console.ReadKey (<span class="pl-c1">true</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}</pre></div>
|
||||
|
||||
<h4>
|
||||
<a id="step-1" class="anchor" href="#step-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 1</h4>
|
||||
|
||||
<p>Required namespace.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> WebSocketSharp<span class="pl-k">;</span></pre></div>
|
||||
|
||||
<p>The <code>WebSocket</code> class exists in the <code>WebSocketSharp</code> namespace.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-2" class="anchor" href="#step-2" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 2</h4>
|
||||
|
||||
<p>Creating a new instance of the <code>WebSocket</code> class with the WebSocket URL to connect.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> (var ws = new WebSocket ("ws://example.com")) {
|
||||
...
|
||||
}</pre></div>
|
||||
|
||||
<p>The <code>WebSocket</code> class inherits the <code>System.IDisposable</code> interface, so you can use the <code>using</code> statement. And the WebSocket connection will be closed with close status <code>1001</code> (going away) when the control leaves the <code>using</code> block.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-3" class="anchor" href="#step-3" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 3</h4>
|
||||
|
||||
<p>Setting the <code>WebSocket</code> events.</p>
|
||||
|
||||
<h5>
|
||||
<a id="websocketonopen-event" class="anchor" href="#websocketonopen-event" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket.OnOpen Event</h5>
|
||||
|
||||
<p>A <code>WebSocket.OnOpen</code> event occurs when the WebSocket connection has been established.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.OnOpen += (sender, e) => {
|
||||
...
|
||||
};</pre></div>
|
||||
|
||||
<p><code>e</code> has passed as the <code>System.EventArgs.Empty</code>, so you don't need to use it.</p>
|
||||
|
||||
<h5>
|
||||
<a id="websocketonmessage-event" class="anchor" href="#websocketonmessage-event" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket.OnMessage Event</h5>
|
||||
|
||||
<p>A <code>WebSocket.OnMessage</code> event occurs when the <code>WebSocket</code> receives a message.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.OnMessage += (sender, e) => {
|
||||
...
|
||||
};</pre></div>
|
||||
|
||||
<p><code>e</code> has passed as a <code>WebSocketSharp.MessageEventArgs</code>.</p>
|
||||
|
||||
<p>If you would like to get the message data, you should access <code>e.Data</code> or <code>e.RawData</code> property.</p>
|
||||
|
||||
<p>And you can determine which property you should access by checking <code>e.IsText</code> or <code>e.IsBinary</code> property.</p>
|
||||
|
||||
<p>If <code>e.IsText</code> is <code>true</code>, you should access <code>e.Data</code> that returns a <code>string</code> (represents a <strong>text</strong> message).</p>
|
||||
|
||||
<p>Or if <code>e.IsBinary</code> is <code>true</code>, you should access <code>e.RawData</code> that returns a <code>byte[]</code> (represents a <strong>binary</strong> message).</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">if</span> (e.IsText) {
|
||||
<span class="pl-c">// Do something with e.Data.</span>
|
||||
...
|
||||
|
||||
<span class="pl-k">return</span>;
|
||||
}
|
||||
|
||||
<span class="pl-k">if</span> (e.IsBinary) {
|
||||
<span class="pl-c">// Do something with e.RawData.</span>
|
||||
...
|
||||
|
||||
<span class="pl-k">return</span>;
|
||||
}</pre></div>
|
||||
|
||||
<p>And if you would like to notify that a <strong>ping</strong> has been received, via this event, you should set the <code>WebSocket.EmitOnPing</code> property to <code>true</code>, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.EmitOnPing = <span class="pl-c1">true</span>;
|
||||
ws.OnMessage += (sender, e) => {
|
||||
<span class="pl-k">if</span> (e.IsPing) {
|
||||
<span class="pl-c">// Do something to notify that a ping has been received.</span>
|
||||
...
|
||||
|
||||
<span class="pl-k">return</span>;
|
||||
}
|
||||
};</pre></div>
|
||||
|
||||
<h5>
|
||||
<a id="websocketonerror-event" class="anchor" href="#websocketonerror-event" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket.OnError Event</h5>
|
||||
|
||||
<p>A <code>WebSocket.OnError</code> event occurs when the <code>WebSocket</code> gets an error.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.OnError += (sender, e) => {
|
||||
...
|
||||
};</pre></div>
|
||||
|
||||
<p><code>e</code> has passed as a <code>WebSocketSharp.ErrorEventArgs</code>.</p>
|
||||
|
||||
<p><code>e.Message</code> property returns a <code>string</code> that represents the error message.</p>
|
||||
|
||||
<p>If the error is due to an exception, <code>e.Exception</code> property returns a <code>System.Exception</code> instance that caused the error.</p>
|
||||
|
||||
<h5>
|
||||
<a id="websocketonclose-event" class="anchor" href="#websocketonclose-event" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket.OnClose Event</h5>
|
||||
|
||||
<p>A <code>WebSocket.OnClose</code> event occurs when the WebSocket connection has been closed.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.OnClose += (sender, e) => {
|
||||
...
|
||||
};</pre></div>
|
||||
|
||||
<p><code>e</code> has passed as a <code>WebSocketSharp.CloseEventArgs</code>.</p>
|
||||
|
||||
<p><code>e.Code</code> property returns a <code>ushort</code> that represents the status code for the close, and <code>e.Reason</code> property returns a <code>string</code> that represents the reason for the close.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-4" class="anchor" href="#step-4" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 4</h4>
|
||||
|
||||
<p>Connecting to the WebSocket server.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Connect ();</pre></div>
|
||||
|
||||
<p>If you would like to connect to the server asynchronously, you should use the <code>WebSocket.ConnectAsync ()</code> method.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-5" class="anchor" href="#step-5" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 5</h4>
|
||||
|
||||
<p>Sending data to the WebSocket server.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Send (data);</pre></div>
|
||||
|
||||
<p>The <code>WebSocket.Send</code> method is overloaded.</p>
|
||||
|
||||
<p>You can use the <code>WebSocket.Send (string)</code>, <code>WebSocket.Send (byte[])</code>, or <code>WebSocket.Send (System.IO.FileInfo)</code> method to send the data.</p>
|
||||
|
||||
<p>If you would like to send the data asynchronously, you should use the <code>WebSocket.SendAsync</code> method.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.SendAsync (data, completed);</pre></div>
|
||||
|
||||
<p>And also if you would like to do something when the send is complete, you should set <code>completed</code> to any <code>Action<bool></code> delegate.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-6" class="anchor" href="#step-6" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 6</h4>
|
||||
|
||||
<p>Closing the WebSocket connection.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Close (code, reason);</pre></div>
|
||||
|
||||
<p>If you would like to close the connection explicitly, you should use the <code>WebSocket.Close</code> method.</p>
|
||||
|
||||
<p>The <code>WebSocket.Close</code> method is overloaded.</p>
|
||||
|
||||
<p>You can use the <code>WebSocket.Close ()</code>, <code>WebSocket.Close (ushort)</code>, <code>WebSocket.Close (WebSocketSharp.CloseStatusCode)</code>, <code>WebSocket.Close (ushort, string)</code>, or <code>WebSocket.Close (WebSocketSharp.CloseStatusCode, string)</code> method to close the connection.</p>
|
||||
|
||||
<p>If you would like to close the connection asynchronously, you should use the <code>WebSocket.CloseAsync</code> method.</p>
|
||||
|
||||
<h3>
|
||||
<a id="websocket-server" class="anchor" href="#websocket-server" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket Server</h3>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> System<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp.Server<span class="pl-k">;</span>
|
||||
|
||||
<span class="pl-k">namespace</span> <span class="pl-en">Example</span>
|
||||
{
|
||||
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Laputa</span> : <span class="pl-k">WebSocketBehavior</span>
|
||||
{
|
||||
<span class="pl-k">protected</span> <span class="pl-k">override</span> <span class="pl-k">void</span> <span class="pl-en">OnMessage</span> (<span class="pl-k">MessageEventArgs</span> <span class="pl-smi">e</span>)
|
||||
{
|
||||
<span class="pl-k">var</span> msg = e.Data == <span class="pl-s"><span class="pl-pds">"</span>BALUS<span class="pl-pds">"</span></span>
|
||||
? <span class="pl-s"><span class="pl-pds">"</span>I've been balused already...<span class="pl-pds">"</span></span>
|
||||
: <span class="pl-s"><span class="pl-pds">"</span>I'm not available now.<span class="pl-pds">"</span></span>;
|
||||
|
||||
Send (msg);
|
||||
}
|
||||
}
|
||||
|
||||
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Program</span>
|
||||
{
|
||||
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-k">void</span> <span class="pl-en">Main</span> (<span class="pl-k">string[]</span> <span class="pl-smi">args</span>)
|
||||
{
|
||||
<span class="pl-k">var</span> wssv = <span class="pl-k">new</span> WebSocketServer (<span class="pl-s"><span class="pl-pds">"</span>ws://dragonsnest.far<span class="pl-pds">"</span></span>);
|
||||
wssv.AddWebSocketService<Laputa> (<span class="pl-s"><span class="pl-pds">"</span>/Laputa<span class="pl-pds">"</span></span>);
|
||||
wssv.Start ();
|
||||
Console.ReadKey (<span class="pl-c1">true</span>);
|
||||
wssv.Stop ();
|
||||
}
|
||||
}
|
||||
}</pre></div>
|
||||
|
||||
<h4>
|
||||
<a id="step-1-1" class="anchor" href="#step-1-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 1</h4>
|
||||
|
||||
<p>Required namespace.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> WebSocketSharp.Server<span class="pl-k">;</span></pre></div>
|
||||
|
||||
<p>The <code>WebSocketBehavior</code> and <code>WebSocketServer</code> classes exist in the <code>WebSocketSharp.Server</code> namespace.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-2-1" class="anchor" href="#step-2-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 2</h4>
|
||||
|
||||
<p>Creating the class that inherits the <code>WebSocketBehavior</code> class.</p>
|
||||
|
||||
<p>For example, if you would like to provide an echo service,</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> System<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp.Server<span class="pl-k">;</span>
|
||||
|
||||
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Echo</span> : <span class="pl-k">WebSocketBehavior</span>
|
||||
{
|
||||
<span class="pl-k">protected</span> <span class="pl-k">override</span> <span class="pl-k">void</span> <span class="pl-en">OnMessage</span> (<span class="pl-k">MessageEventArgs</span> <span class="pl-smi">e</span>)
|
||||
{
|
||||
Send (e.Data);
|
||||
}
|
||||
}</pre></div>
|
||||
|
||||
<p>And if you would like to provide a chat service,</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> System<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp<span class="pl-k">;</span>
|
||||
<span class="pl-k">using</span> WebSocketSharp.Server<span class="pl-k">;</span>
|
||||
|
||||
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Chat</span> : <span class="pl-k">WebSocketBehavior</span>
|
||||
{
|
||||
<span class="pl-k">private</span> <span class="pl-k">string</span> _suffix;
|
||||
|
||||
<span class="pl-k">public</span> <span class="pl-en">Chat</span> ()
|
||||
: <span class="pl-c1">this</span> (null)
|
||||
{
|
||||
}
|
||||
|
||||
<span class="pl-k">public</span> <span class="pl-en">Chat</span> (<span class="pl-k">string</span> <span class="pl-smi">suffix</span>)
|
||||
{
|
||||
_suffix = suffix ?? String.Empty;
|
||||
}
|
||||
|
||||
<span class="pl-k">protected</span> <span class="pl-k">override</span> <span class="pl-k">void</span> <span class="pl-en">OnMessage</span> (<span class="pl-k">MessageEventArgs</span> <span class="pl-smi">e</span>)
|
||||
{
|
||||
Sessions.Broadcast (e.Data + _suffix);
|
||||
}
|
||||
}</pre></div>
|
||||
|
||||
<p>You can define the behavior of any WebSocket service by creating the class that inherits the <code>WebSocketBehavior</code> class.</p>
|
||||
|
||||
<p>If you override the <code>WebSocketBehavior.OnMessage (MessageEventArgs)</code> method, it will be called when the <code>WebSocket</code> used in a session in the service receives a message.</p>
|
||||
|
||||
<p>And if you override the <code>WebSocketBehavior.OnOpen ()</code>, <code>WebSocketBehavior.OnError (ErrorEventArgs)</code>, and <code>WebSocketBehavior.OnClose (CloseEventArgs)</code> methods, each of them will be called when each of the <code>WebSocket</code> events (<code>OnOpen</code>, <code>OnError</code>, and <code>OnClose</code>) occurs.</p>
|
||||
|
||||
<p>The <code>WebSocketBehavior.Send</code> method can send data to the client on a session in the service.</p>
|
||||
|
||||
<p>If you would like to get the sessions in the service, you should access the <code>WebSocketBehavior.Sessions</code> property (returns a <code>WebSocketSharp.Server.WebSocketSessionManager</code>).</p>
|
||||
|
||||
<p>The <code>WebSocketBehavior.Sessions.Broadcast</code> method can send data to every client in the service.</p>
|
||||
|
||||
<h4>
|
||||
<a id="step-3-1" class="anchor" href="#step-3-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 3</h4>
|
||||
|
||||
<p>Creating a new instance of the <code>WebSocketServer</code> class.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">var</span> wssv = <span class="pl-k">new</span> WebSocketServer (<span class="pl-c1">4649</span>);
|
||||
wssv.AddWebSocketService<Echo> (<span class="pl-s"><span class="pl-pds">"</span>/Echo<span class="pl-pds">"</span></span>);
|
||||
wssv.AddWebSocketService<Chat> (<span class="pl-s"><span class="pl-pds">"</span>/Chat<span class="pl-pds">"</span></span>);
|
||||
wssv.AddWebSocketService<Chat> (<span class="pl-s"><span class="pl-pds">"</span>/ChatWithNyan<span class="pl-pds">"</span></span>, () => <span class="pl-k">new</span> Chat (<span class="pl-s"><span class="pl-pds">"</span> Nyan!<span class="pl-pds">"</span></span>));</pre></div>
|
||||
|
||||
<p>You can add any WebSocket service to your <code>WebSocketServer</code> with the specified behavior and path to the service, by using the <code>WebSocketServer.AddWebSocketService<TBehaviorWithNew> (string)</code> or <code>WebSocketServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)</code> method.</p>
|
||||
|
||||
<p>The type of <code>TBehaviorWithNew</code> must inherit the <code>WebSocketBehavior</code> class, and must have a public parameterless constructor.</p>
|
||||
|
||||
<p>And also the type of <code>TBehavior</code> must inherit the <code>WebSocketBehavior</code> class.</p>
|
||||
|
||||
<p>So you can use the classes created in <strong>Step 2</strong> to add the service.</p>
|
||||
|
||||
<p>If you create a instance of the <code>WebSocketServer</code> class without a port number, the <code>WebSocketServer</code> class set the port number to <strong>80</strong> automatically. So it's necessary to run with root permission.</p>
|
||||
|
||||
<pre><code>$ sudo mono example2.exe
|
||||
</code></pre>
|
||||
|
||||
<h4>
|
||||
<a id="step-4-1" class="anchor" href="#step-4-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 4</h4>
|
||||
|
||||
<p>Starting the WebSocket server.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.Start ();</pre></div>
|
||||
|
||||
<h4>
|
||||
<a id="step-5-1" class="anchor" href="#step-5-1" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Step 5</h4>
|
||||
|
||||
<p>Stopping the WebSocket server.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.Stop (code, reason);</pre></div>
|
||||
|
||||
<p>The <code>WebSocketServer.Stop</code> method is overloaded.</p>
|
||||
|
||||
<p>You can use the <code>WebSocketServer.Stop ()</code>, <code>WebSocketServer.Stop (ushort, string)</code>, or <code>WebSocketServer.Stop (WebSocketSharp.CloseStatusCode, string)</code> method to stop the server.</p>
|
||||
|
||||
<h3>
|
||||
<a id="http-server-with-the-websocket" class="anchor" href="#http-server-with-the-websocket" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>HTTP Server with the WebSocket</h3>
|
||||
|
||||
<p>I have modified the <code>System.Net.HttpListener</code>, <code>System.Net.HttpListenerContext</code>, and some other classes from <strong><a href="http://www.mono-project.com">Mono</a></strong> to create an HTTP server that allows to accept the WebSocket handshake requests.</p>
|
||||
|
||||
<p>So websocket-sharp provides the <code>WebSocketSharp.Server.HttpServer</code> class.</p>
|
||||
|
||||
<p>You can add any WebSocket service to your <code>HttpServer</code> with the specified behavior and path to the service, by using the <code>HttpServer.AddWebSocketService<TBehaviorWithNew> (string)</code> or <code>HttpServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)</code> method.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">var</span> httpsv = <span class="pl-k">new</span> HttpServer (<span class="pl-c1">4649</span>);
|
||||
httpsv.AddWebSocketService<Echo> (<span class="pl-s"><span class="pl-pds">"</span>/Echo<span class="pl-pds">"</span></span>);
|
||||
httpsv.AddWebSocketService<Chat> (<span class="pl-s"><span class="pl-pds">"</span>/Chat<span class="pl-pds">"</span></span>);
|
||||
httpsv.AddWebSocketService<Chat> (<span class="pl-s"><span class="pl-pds">"</span>/ChatWithNyan<span class="pl-pds">"</span></span>, () => <span class="pl-k">new</span> Chat (<span class="pl-s"><span class="pl-pds">"</span> Nyan!<span class="pl-pds">"</span></span>));</pre></div>
|
||||
|
||||
<p>For more information, would you see <strong><a href="https://github.com/sta/websocket-sharp/tree/master/Example3">Example3</a></strong>?</p>
|
||||
|
||||
<h3>
|
||||
<a id="websocket-extensions" class="anchor" href="#websocket-extensions" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>WebSocket Extensions</h3>
|
||||
|
||||
<h4>
|
||||
<a id="per-message-compression" class="anchor" href="#per-message-compression" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Per-message Compression</h4>
|
||||
|
||||
<p>websocket-sharp supports the <strong><a href="http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19">Per-message Compression</a></strong> extension (but doesn't support this extension with the <a href="http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19#section-8.1.1">context take over</a>).</p>
|
||||
|
||||
<p>As a WebSocket client, if you would like to enable this extension, you should set such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Compression = CompressionMethod.Deflate;</pre></div>
|
||||
|
||||
<p>And then your client will send the following header in the handshake request to the server.</p>
|
||||
|
||||
<pre><code>Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover
|
||||
</code></pre>
|
||||
|
||||
<p>If the server accepts this extension, it will return the same header which has the corresponding value. And when your client receives it, this extension will be available.</p>
|
||||
|
||||
<h4>
|
||||
<a id="ignoring-the-extensions" class="anchor" href="#ignoring-the-extensions" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Ignoring the extensions</h4>
|
||||
|
||||
<p>As a WebSocket server, if you would like to ignore the extensions requested from a client, you should set the <code>WebSocketBehavior.IgnoreExtensions</code> property to <code>true</code> in your <code>WebSocketBehavior</code> constructor or initializing it, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.AddWebSocketService<Chat> (
|
||||
<span class="pl-s"><span class="pl-pds">"</span>/Chat<span class="pl-pds">"</span></span>,
|
||||
() =>
|
||||
<span class="pl-k">new</span> Chat () {
|
||||
<span class="pl-c">// To ignore the extensions requested from a client.</span>
|
||||
IgnoreExtensions = <span class="pl-c1">true</span>
|
||||
}
|
||||
);</pre></div>
|
||||
|
||||
<p>If it's set to <code>true</code>, the service will not return the <strong>Sec-WebSocket-Extensions</strong> header in its handshake response.</p>
|
||||
|
||||
<p>I think this is useful when you get something error in connecting the server and exclude the extensions as a cause of the error.</p>
|
||||
|
||||
<h3>
|
||||
<a id="secure-connection" class="anchor" href="#secure-connection" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Secure Connection</h3>
|
||||
|
||||
<p>websocket-sharp supports the <strong>Secure Connection</strong> with <strong>SSL/TLS</strong>.</p>
|
||||
|
||||
<p>As a <strong>WebSocket Client</strong>, you should create a new instance of the <code>WebSocket</code> class with the <strong>wss</strong> scheme WebSocket URL.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> (var ws = new WebSocket ("wss://example.com")) {
|
||||
...
|
||||
}</pre></div>
|
||||
|
||||
<p>And if you would like to use the custom validation for the server certificate, you should set the <code>WebSocket.SslConfiguration.ServerCertificateValidationCallback</code> property.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.SslConfiguration.ServerCertificateValidationCallback =
|
||||
(sender, certificate, chain, sslPolicyErrors) => {
|
||||
<span class="pl-c">// Do something to validate the server certificate.</span>
|
||||
...
|
||||
|
||||
<span class="pl-k">return</span> <span class="pl-c1">true</span>; <span class="pl-c">// If the server certificate is valid.</span>
|
||||
};</pre></div>
|
||||
|
||||
<p>If you set this property to nothing, the validation does nothing with the server certificate, and returns <code>true</code>.</p>
|
||||
|
||||
<p>As a <strong>WebSocket Server</strong>, you should create a new instance of the <code>WebSocketServer</code> or <code>HttpServer</code> class with some settings for secure connection, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">var</span> wssv = <span class="pl-k">new</span> WebSocketServer (<span class="pl-c1">5963</span>, <span class="pl-c1">true</span>);
|
||||
wssv.SslConfiguration.ServerCertificate =
|
||||
<span class="pl-k">new</span> X509Certificate2 (<span class="pl-s"><span class="pl-pds">"</span>/path/to/cert.pfx<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>password for cert.pfx<span class="pl-pds">"</span></span>);</pre></div>
|
||||
|
||||
<h3>
|
||||
<a id="http-authentication" class="anchor" href="#http-authentication" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>HTTP Authentication</h3>
|
||||
|
||||
<p>websocket-sharp supports the <strong><a href="http://tools.ietf.org/html/rfc2617">HTTP Authentication (Basic/Digest)</a></strong>.</p>
|
||||
|
||||
<p>As a <strong>WebSocket Client</strong>, you should set a pair of user name and password for the HTTP authentication, by using the <code>WebSocket.SetCredentials (string, string, bool)</code> method before connecting.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.SetCredentials (<span class="pl-s"><span class="pl-pds">"</span>nobita<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>password<span class="pl-pds">"</span></span>, preAuth);</pre></div>
|
||||
|
||||
<p>If <code>preAuth</code> is <code>true</code>, the <code>WebSocket</code> sends the Basic authentication credentials with the first handshake request to the server.</p>
|
||||
|
||||
<p>Or if <code>preAuth</code> is <code>false</code>, the <code>WebSocket</code> sends either the Basic or Digest (determined by the unauthorized response to the first handshake request) authentication credentials with the second handshake request to the server.</p>
|
||||
|
||||
<p>As a <strong>WebSocket Server</strong>, you should set an HTTP authentication scheme, a realm, and any function to find the user credentials before starting, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.AuthenticationSchemes = AuthenticationSchemes.Basic;
|
||||
wssv.Realm = <span class="pl-s"><span class="pl-pds">"</span>WebSocket Test<span class="pl-pds">"</span></span>;
|
||||
wssv.UserCredentialsFinder = id => {
|
||||
<span class="pl-k">var</span> name = id.Name;
|
||||
|
||||
<span class="pl-c">// Return user name, password, and roles.</span>
|
||||
<span class="pl-k">return</span> name == <span class="pl-s"><span class="pl-pds">"</span>nobita<span class="pl-pds">"</span></span>
|
||||
? <span class="pl-k">new</span> NetworkCredential (name, <span class="pl-s"><span class="pl-pds">"</span>password<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>gunfighter<span class="pl-pds">"</span></span>)
|
||||
: <span class="pl-c1">null</span>; <span class="pl-c">// If the user credentials aren't found.</span>
|
||||
};</pre></div>
|
||||
|
||||
<p>If you would like to provide the Digest authentication, you should set such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.AuthenticationSchemes = AuthenticationSchemes.Digest;</pre></div>
|
||||
|
||||
<h3>
|
||||
<a id="query-string-origin-header-and-cookies" class="anchor" href="#query-string-origin-header-and-cookies" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Query String, Origin header and Cookies</h3>
|
||||
|
||||
<p>As a <strong>WebSocket Client</strong>, if you would like to send the <strong>Query String</strong> with the handshake request to the server, you should create a new instance of the <code>WebSocket</code> class with the WebSocket URL that includes the <a href="http://tools.ietf.org/html/rfc3986#section-3.4">Query</a> string parameters.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">using</span> (var ws = new WebSocket ("ws://example.com/?name=nobita")) {
|
||||
...
|
||||
}</pre></div>
|
||||
|
||||
<p>And if you would like to send the <strong>Origin</strong> header with the handshake request to the server, you should set the <code>WebSocket.Origin</code> property to an allowable value as the <a href="http://tools.ietf.org/html/rfc6454#section-7">Origin</a> header before connecting, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Origin = <span class="pl-s"><span class="pl-pds">"</span>http://example.com<span class="pl-pds">"</span></span>;</pre></div>
|
||||
|
||||
<p>And also if you would like to send the <strong>Cookies</strong> with the handshake request to the server, you should set any cookie by using the <code>WebSocket.SetCookie (WebSocketSharp.Net.Cookie)</code> method before connecting, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.SetCookie (<span class="pl-k">new</span> Cookie (<span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>nobita<span class="pl-pds">"</span></span>));</pre></div>
|
||||
|
||||
<p>As a <strong>WebSocket Server</strong>, if you would like to get the <strong>Query String</strong> included in a handshake request, you should access the <code>WebSocketBehavior.Context.QueryString</code> property, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-en">Chat</span> : <span class="pl-k">WebSocketBehavior</span>
|
||||
{
|
||||
<span class="pl-k">private</span> <span class="pl-k">string</span> _name;
|
||||
...
|
||||
|
||||
<span class="pl-k">protected</span> <span class="pl-k">override</span> <span class="pl-k">void</span> <span class="pl-en">OnOpen</span> ()
|
||||
{
|
||||
_name = Context.QueryString[<span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>];
|
||||
}
|
||||
|
||||
...
|
||||
}</pre></div>
|
||||
|
||||
<p>And if you would like to validate the <strong>Origin</strong> header, <strong>Cookies</strong>, or both included in a handshake request, you should set each validation with your <code>WebSocketBehavior</code>, for example, by using the <code>AddWebSocketService<TBehavior> (string, Func<TBehavior>)</code> method with initializing, such as the following.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>wssv.AddWebSocketService<Chat> (
|
||||
<span class="pl-s"><span class="pl-pds">"</span>/Chat<span class="pl-pds">"</span></span>,
|
||||
() =>
|
||||
<span class="pl-k">new</span> Chat () {
|
||||
OriginValidator = val => {
|
||||
<span class="pl-c">// Check the value of the Origin header, and return true if valid.</span>
|
||||
Uri origin;
|
||||
<span class="pl-k">return</span> !val.IsNullOrEmpty ()
|
||||
&& Uri.TryCreate (val, UriKind.Absolute, out origin)
|
||||
&& origin.Host == <span class="pl-s"><span class="pl-pds">"</span>example.com<span class="pl-pds">"</span></span>;
|
||||
},
|
||||
CookiesValidator = (req, res) => {
|
||||
<span class="pl-c">// Check the cookies in 'req', and set the cookies to send to</span>
|
||||
<span class="pl-c">// the client with 'res' if necessary.</span>
|
||||
<span class="pl-k">foreach</span> (Cookie cookie <span class="pl-k">in</span> req) {
|
||||
cookie.Expired = <span class="pl-c1">true</span>;
|
||||
res.Add (cookie);
|
||||
}
|
||||
|
||||
<span class="pl-k">return</span> <span class="pl-c1">true</span>; <span class="pl-c">// If valid.</span>
|
||||
}
|
||||
}
|
||||
);</pre></div>
|
||||
|
||||
<p>And also if you would like to get each value of the Origin header and cookies, you should access each of the <code>WebSocketBehavior.Context.Origin</code> and <code>WebSocketBehavior.Context.CookieCollection</code> properties.</p>
|
||||
|
||||
<h3>
|
||||
<a id="connecting-through-the-http-proxy-server" class="anchor" href="#connecting-through-the-http-proxy-server" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Connecting through the HTTP Proxy server</h3>
|
||||
|
||||
<p>websocket-sharp supports to connect through the <strong>HTTP Proxy</strong> server.</p>
|
||||
|
||||
<p>If you would like to connect to a WebSocket server through the HTTP proxy server, you should set the proxy server URL, and if necessary, a pair of user name and password for the proxy server authentication (Basic/Digest), by using the <code>WebSocket.SetProxy (string, string, string)</code> method before connecting.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre><span class="pl-k">var</span> ws = <span class="pl-k">new</span> WebSocket (<span class="pl-s"><span class="pl-pds">"</span>ws://example.com<span class="pl-pds">"</span></span>);
|
||||
ws.SetProxy (<span class="pl-s"><span class="pl-pds">"</span>http://localhost:3128<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>nobita<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>password<span class="pl-pds">"</span></span>);</pre></div>
|
||||
|
||||
<p>I have tested this with <strong><a href="http://www.squid-cache.org">Squid</a></strong>. It's necessary to disable the following configuration option in <strong>squid.conf</strong> (e.g. <code>/etc/squid/squid.conf</code>).</p>
|
||||
|
||||
<pre><code># Deny CONNECT to other than SSL ports
|
||||
#http_access deny CONNECT !SSL_ports
|
||||
</code></pre>
|
||||
|
||||
<h3>
|
||||
<a id="logging" class="anchor" href="#logging" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Logging</h3>
|
||||
|
||||
<p>The <code>WebSocket</code> class has the own logging function.</p>
|
||||
|
||||
<p>You can use it with the <code>WebSocket.Log</code> property (returns a <code>WebSocketSharp.Logger</code>).</p>
|
||||
|
||||
<p>So if you would like to change the current logging level (<code>WebSocketSharp.LogLevel.Error</code> as the default), you should set the <code>WebSocket.Log.Level</code> property to any of the <code>LogLevel</code> enum values.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Log.Level = LogLevel.Debug;</pre></div>
|
||||
|
||||
<p>The above means a log with lower than <code>LogLevel.Debug</code> cannot be outputted.</p>
|
||||
|
||||
<p>And if you would like to output a log, you should use any of the output methods. The following outputs a log with <code>LogLevel.Debug</code>.</p>
|
||||
|
||||
<div class="highlight highlight-source-cs"><pre>ws.Log.Debug (<span class="pl-s"><span class="pl-pds">"</span>This is a debug message.<span class="pl-pds">"</span></span>);</pre></div>
|
||||
|
||||
<p>The <code>WebSocketServer</code> and <code>HttpServer</code> classes have the same logging function.</p>
|
||||
|
||||
<h2>
|
||||
<a id="examples" class="anchor" href="#examples" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Examples</h2>
|
||||
|
||||
<p>Examples using websocket-sharp.</p>
|
||||
|
||||
<h3>
|
||||
<a id="example" class="anchor" href="#example" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Example</h3>
|
||||
|
||||
<p><strong><a href="https://github.com/sta/websocket-sharp/tree/master/Example">Example</a></strong> connects to the <strong><a href="http://www.websocket.org/echo.html">Echo server</a></strong> with the WebSocket.</p>
|
||||
|
||||
<h3>
|
||||
<a id="example2" class="anchor" href="#example2" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Example2</h3>
|
||||
|
||||
<p><strong><a href="https://github.com/sta/websocket-sharp/tree/master/Example2">Example2</a></strong> starts a WebSocket server.</p>
|
||||
|
||||
<h3>
|
||||
<a id="example3" class="anchor" href="#example3" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Example3</h3>
|
||||
|
||||
<p><strong><a href="https://github.com/sta/websocket-sharp/tree/master/Example3">Example3</a></strong> starts an HTTP server that allows to accept the WebSocket handshake requests.</p>
|
||||
|
||||
<p>Would you access to <a href="http://localhost:4649">http://localhost:4649</a> to do <strong>WebSocket Echo Test</strong> with your web browser while Example3 is running?</p>
|
||||
|
||||
<h2>
|
||||
<a id="supported-websocket-specifications" class="anchor" href="#supported-websocket-specifications" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Supported WebSocket Specifications</h2>
|
||||
|
||||
<p>websocket-sharp supports <strong><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a></strong>, and it's based on the following WebSocket references:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="http://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a></strong></li>
|
||||
<li><strong><a href="http://www.w3.org/TR/websockets">The WebSocket API</a></strong></li>
|
||||
<li><strong><a href="http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19">Compression Extensions for WebSocket</a></strong></li>
|
||||
</ul>
|
||||
|
||||
<p>Thanks for translating to japanese.</p>
|
||||
|
||||
<ul>
|
||||
<li><strong><a href="http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html">The WebSocket Protocol 日本語訳</a></strong></li>
|
||||
<li><strong><a href="http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html">The WebSocket API 日本語訳</a></strong></li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
<a id="license" class="anchor" href="#license" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>License</h2>
|
||||
|
||||
<p>websocket-sharp is provided under <strong><a href="https://raw.github.com/sta/websocket-sharp/master/LICENSE.txt">The MIT License</a></strong>.</p>
|
||||
|
||||
<footer class="site-footer">
|
||||
<span class="site-footer-owner"><a href="https://github.com/sta/websocket-sharp">websocket-sharp</a> is maintained by <a href="https://github.com/sta">sta</a>.</span>
|
||||
|
||||
<span class="site-footer-credits">This page was generated by <a href="https://pages.github.com">GitHub Pages</a> using the <a href="https://github.com/jasonlong/cayman-theme">Cayman theme</a> by <a href="https://twitter.com/jasonlong">Jason Long</a>.</span>
|
||||
</footer>
|
||||
|
||||
</section>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
try {
|
||||
var pageTracker = _gat._getTracker("UA-9752433-2");
|
||||
pageTracker._trackPageview();
|
||||
} catch(err) {}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
686
index.md
Normal file
686
index.md
Normal file
@ -0,0 +1,686 @@
|
||||
## Welcome to websocket-sharp! ##
|
||||
|
||||
**websocket-sharp** supports:
|
||||
|
||||
- **[RFC 6455](#supported-websocket-specifications)**
|
||||
- **[WebSocket Client](#websocket-client)** and **[Server](#websocket-server)**
|
||||
- **[Per-message Compression](#per-message-compression)** extension
|
||||
- **[Secure Connection](#secure-connection)**
|
||||
- **[HTTP Authentication](#http-authentication)**
|
||||
- **[Query String, Origin header and Cookies](#query-string-origin-header-and-cookies)**
|
||||
- **[Connecting through the HTTP Proxy server](#connecting-through-the-http-proxy-server)**
|
||||
- .NET Framework **3.5** or later (includes compatible environment such as **[Mono]**)
|
||||
|
||||
## Build ##
|
||||
|
||||
websocket-sharp is built as a single assembly, **websocket-sharp.dll**.
|
||||
|
||||
websocket-sharp is developed with **[MonoDevelop]**. So a simple way to build is to open **websocket-sharp.sln** and run build for **websocket-sharp project** with any of the build configurations (e.g. `Debug`) in MonoDevelop.
|
||||
|
||||
## Install ##
|
||||
|
||||
### Self Build ###
|
||||
|
||||
You should add your **websocket-sharp.dll** (e.g. `/path/to/websocket-sharp/bin/Debug/websocket-sharp.dll`) to the library references of your project.
|
||||
|
||||
If you would like to use that dll in your **[Unity]** project, you should add it to any folder of your project (e.g. `Assets/Plugins`) in **Unity Editor**.
|
||||
|
||||
### NuGet Gallery ###
|
||||
|
||||
websocket-sharp is available on the **[NuGet Gallery]**, as still a **prerelease** version.
|
||||
|
||||
- **[NuGet Gallery: websocket-sharp]**
|
||||
|
||||
You can add websocket-sharp to your project with the **NuGet Package Manager**, by using the following command in the **Package Manager Console**.
|
||||
|
||||
PM> Install-Package WebSocketSharp -Pre
|
||||
|
||||
### Unity Asset Store ###
|
||||
|
||||
websocket-sharp is available on the **Unity Asset Store**.
|
||||
|
||||
- **[WebSocket-Sharp for Unity]**
|
||||
|
||||
It works with **Unity Free**, but there are some limitations:
|
||||
|
||||
- **[Security Sandbox of the Webplayer]** (The server isn't available in Web Player)
|
||||
- **[WebGL Networking]** (Not available in WebGL)
|
||||
- **Incompatible platform** (Not available for such UWP)
|
||||
- **Limited support for the System.IO.Compression** (The compression extension isn't available on Windows)
|
||||
- **.NET Socket Support for iOS/Android** (It requires iOS/Android Pro if your Unity is earlier than Unity 5)
|
||||
- **.NET API 2.0 compatibility level for iOS/Android**
|
||||
|
||||
**.NET API 2.0 compatibility level for iOS/Android** may require to fix lack of some features for later than .NET 2.0, such as the `System.Func<...>` delegates (so i have added them in that asset package).
|
||||
|
||||
And it's priced at **US$15**. I think your $15 makes this project more better and accelerated, **Thank you!**
|
||||
|
||||
## Usage ##
|
||||
|
||||
### WebSocket Client ###
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using WebSocketSharp;
|
||||
|
||||
namespace Example
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
using (var ws = new WebSocket ("ws://dragonsnest.far/Laputa")) {
|
||||
ws.OnMessage += (sender, e) =>
|
||||
Console.WriteLine ("Laputa says: " + e.Data);
|
||||
|
||||
ws.Connect ();
|
||||
ws.Send ("BALUS");
|
||||
Console.ReadKey (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 1 ####
|
||||
|
||||
Required namespace.
|
||||
|
||||
```csharp
|
||||
using WebSocketSharp;
|
||||
```
|
||||
|
||||
The `WebSocket` class exists in the `WebSocketSharp` namespace.
|
||||
|
||||
#### Step 2 ####
|
||||
|
||||
Creating a new instance of the `WebSocket` class with the WebSocket URL to connect.
|
||||
|
||||
```csharp
|
||||
using (var ws = new WebSocket ("ws://example.com")) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The `WebSocket` class inherits the `System.IDisposable` interface, so you can use the `using` statement. And the WebSocket connection will be closed with close status `1001` (going away) when the control leaves the `using` block.
|
||||
|
||||
#### Step 3 ####
|
||||
|
||||
Setting the `WebSocket` events.
|
||||
|
||||
##### WebSocket.OnOpen Event #####
|
||||
|
||||
A `WebSocket.OnOpen` event occurs when the WebSocket connection has been established.
|
||||
|
||||
```csharp
|
||||
ws.OnOpen += (sender, e) => {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
`e` has passed as the `System.EventArgs.Empty`, so you don't need to use it.
|
||||
|
||||
##### WebSocket.OnMessage Event #####
|
||||
|
||||
A `WebSocket.OnMessage` event occurs when the `WebSocket` receives a message.
|
||||
|
||||
```csharp
|
||||
ws.OnMessage += (sender, e) => {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
`e` has passed as a `WebSocketSharp.MessageEventArgs`.
|
||||
|
||||
If you would like to get the message data, you should access `e.Data` or `e.RawData` property.
|
||||
|
||||
And you can determine which property you should access by checking `e.IsText` or `e.IsBinary` property.
|
||||
|
||||
If `e.IsText` is `true`, you should access `e.Data` that returns a `string` (represents a **text** message).
|
||||
|
||||
Or if `e.IsBinary` is `true`, you should access `e.RawData` that returns a `byte[]` (represents a **binary** message).
|
||||
|
||||
```csharp
|
||||
if (e.IsText) {
|
||||
// Do something with e.Data.
|
||||
...
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.IsBinary) {
|
||||
// Do something with e.RawData.
|
||||
...
|
||||
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
And if you would like to notify that a **ping** has been received, via this event, you should set the `WebSocket.EmitOnPing` property to `true`, such as the following.
|
||||
|
||||
```csharp
|
||||
ws.EmitOnPing = true;
|
||||
ws.OnMessage += (sender, e) => {
|
||||
if (e.IsPing) {
|
||||
// Do something to notify that a ping has been received.
|
||||
...
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
##### WebSocket.OnError Event #####
|
||||
|
||||
A `WebSocket.OnError` event occurs when the `WebSocket` gets an error.
|
||||
|
||||
```csharp
|
||||
ws.OnError += (sender, e) => {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
`e` has passed as a `WebSocketSharp.ErrorEventArgs`.
|
||||
|
||||
`e.Message` property returns a `string` that represents the error message.
|
||||
|
||||
If the error is due to an exception, `e.Exception` property returns a `System.Exception` instance that caused the error.
|
||||
|
||||
##### WebSocket.OnClose Event #####
|
||||
|
||||
A `WebSocket.OnClose` event occurs when the WebSocket connection has been closed.
|
||||
|
||||
```csharp
|
||||
ws.OnClose += (sender, e) => {
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
`e` has passed as a `WebSocketSharp.CloseEventArgs`.
|
||||
|
||||
`e.Code` property returns a `ushort` that represents the status code for the close, and `e.Reason` property returns a `string` that represents the reason for the close.
|
||||
|
||||
#### Step 4 ####
|
||||
|
||||
Connecting to the WebSocket server.
|
||||
|
||||
```csharp
|
||||
ws.Connect ();
|
||||
```
|
||||
|
||||
If you would like to connect to the server asynchronously, you should use the `WebSocket.ConnectAsync ()` method.
|
||||
|
||||
#### Step 5 ####
|
||||
|
||||
Sending data to the WebSocket server.
|
||||
|
||||
```csharp
|
||||
ws.Send (data);
|
||||
```
|
||||
|
||||
The `WebSocket.Send` method is overloaded.
|
||||
|
||||
You can use the `WebSocket.Send (string)`, `WebSocket.Send (byte[])`, or `WebSocket.Send (System.IO.FileInfo)` method to send the data.
|
||||
|
||||
If you would like to send the data asynchronously, you should use the `WebSocket.SendAsync` method.
|
||||
|
||||
```csharp
|
||||
ws.SendAsync (data, completed);
|
||||
```
|
||||
|
||||
And also if you would like to do something when the send is complete, you should set `completed` to any `Action<bool>` delegate.
|
||||
|
||||
#### Step 6 ####
|
||||
|
||||
Closing the WebSocket connection.
|
||||
|
||||
```csharp
|
||||
ws.Close (code, reason);
|
||||
```
|
||||
|
||||
If you would like to close the connection explicitly, you should use the `WebSocket.Close` method.
|
||||
|
||||
The `WebSocket.Close` method is overloaded.
|
||||
|
||||
You can use the `WebSocket.Close ()`, `WebSocket.Close (ushort)`, `WebSocket.Close (WebSocketSharp.CloseStatusCode)`, `WebSocket.Close (ushort, string)`, or `WebSocket.Close (WebSocketSharp.CloseStatusCode, string)` method to close the connection.
|
||||
|
||||
If you would like to close the connection asynchronously, you should use the `WebSocket.CloseAsync` method.
|
||||
|
||||
### WebSocket Server ###
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using WebSocketSharp;
|
||||
using WebSocketSharp.Server;
|
||||
|
||||
namespace Example
|
||||
{
|
||||
public class Laputa : WebSocketBehavior
|
||||
{
|
||||
protected override void OnMessage (MessageEventArgs e)
|
||||
{
|
||||
var msg = e.Data == "BALUS"
|
||||
? "I've been balused already..."
|
||||
: "I'm not available now.";
|
||||
|
||||
Send (msg);
|
||||
}
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main (string[] args)
|
||||
{
|
||||
var wssv = new WebSocketServer ("ws://dragonsnest.far");
|
||||
wssv.AddWebSocketService<Laputa> ("/Laputa");
|
||||
wssv.Start ();
|
||||
Console.ReadKey (true);
|
||||
wssv.Stop ();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 1 ####
|
||||
|
||||
Required namespace.
|
||||
|
||||
```csharp
|
||||
using WebSocketSharp.Server;
|
||||
```
|
||||
|
||||
The `WebSocketBehavior` and `WebSocketServer` classes exist in the `WebSocketSharp.Server` namespace.
|
||||
|
||||
#### Step 2 ####
|
||||
|
||||
Creating the class that inherits the `WebSocketBehavior` class.
|
||||
|
||||
For example, if you would like to provide an echo service,
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using WebSocketSharp;
|
||||
using WebSocketSharp.Server;
|
||||
|
||||
public class Echo : WebSocketBehavior
|
||||
{
|
||||
protected override void OnMessage (MessageEventArgs e)
|
||||
{
|
||||
Send (e.Data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And if you would like to provide a chat service,
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
using WebSocketSharp;
|
||||
using WebSocketSharp.Server;
|
||||
|
||||
public class Chat : WebSocketBehavior
|
||||
{
|
||||
private string _suffix;
|
||||
|
||||
public Chat ()
|
||||
: this (null)
|
||||
{
|
||||
}
|
||||
|
||||
public Chat (string suffix)
|
||||
{
|
||||
_suffix = suffix ?? String.Empty;
|
||||
}
|
||||
|
||||
protected override void OnMessage (MessageEventArgs e)
|
||||
{
|
||||
Sessions.Broadcast (e.Data + _suffix);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can define the behavior of any WebSocket service by creating the class that inherits the `WebSocketBehavior` class.
|
||||
|
||||
If you override the `WebSocketBehavior.OnMessage (MessageEventArgs)` method, it will be called when the `WebSocket` used in a session in the service receives a message.
|
||||
|
||||
And if you override the `WebSocketBehavior.OnOpen ()`, `WebSocketBehavior.OnError (ErrorEventArgs)`, and `WebSocketBehavior.OnClose (CloseEventArgs)` methods, each of them will be called when each of the `WebSocket` events (`OnOpen`, `OnError`, and `OnClose`) occurs.
|
||||
|
||||
The `WebSocketBehavior.Send` method can send data to the client on a session in the service.
|
||||
|
||||
If you would like to get the sessions in the service, you should access the `WebSocketBehavior.Sessions` property (returns a `WebSocketSharp.Server.WebSocketSessionManager`).
|
||||
|
||||
The `WebSocketBehavior.Sessions.Broadcast` method can send data to every client in the service.
|
||||
|
||||
#### Step 3 ####
|
||||
|
||||
Creating a new instance of the `WebSocketServer` class.
|
||||
|
||||
```csharp
|
||||
var wssv = new WebSocketServer (4649);
|
||||
wssv.AddWebSocketService<Echo> ("/Echo");
|
||||
wssv.AddWebSocketService<Chat> ("/Chat");
|
||||
wssv.AddWebSocketService<Chat> ("/ChatWithNyan", () => new Chat (" Nyan!"));
|
||||
```
|
||||
|
||||
You can add any WebSocket service to your `WebSocketServer` with the specified behavior and path to the service, by using the `WebSocketServer.AddWebSocketService<TBehaviorWithNew> (string)` or `WebSocketServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)` method.
|
||||
|
||||
The type of `TBehaviorWithNew` must inherit the `WebSocketBehavior` class, and must have a public parameterless constructor.
|
||||
|
||||
And also the type of `TBehavior` must inherit the `WebSocketBehavior` class.
|
||||
|
||||
So you can use the classes created in **Step 2** to add the service.
|
||||
|
||||
If you create a instance of the `WebSocketServer` class without a port number, the `WebSocketServer` class set the port number to **80** automatically. So it's necessary to run with root permission.
|
||||
|
||||
$ sudo mono example2.exe
|
||||
|
||||
#### Step 4 ####
|
||||
|
||||
Starting the WebSocket server.
|
||||
|
||||
```csharp
|
||||
wssv.Start ();
|
||||
```
|
||||
|
||||
#### Step 5 ####
|
||||
|
||||
Stopping the WebSocket server.
|
||||
|
||||
```csharp
|
||||
wssv.Stop (code, reason);
|
||||
```
|
||||
|
||||
The `WebSocketServer.Stop` method is overloaded.
|
||||
|
||||
You can use the `WebSocketServer.Stop ()`, `WebSocketServer.Stop (ushort, string)`, or `WebSocketServer.Stop (WebSocketSharp.CloseStatusCode, string)` method to stop the server.
|
||||
|
||||
### HTTP Server with the WebSocket ###
|
||||
|
||||
I have modified the `System.Net.HttpListener`, `System.Net.HttpListenerContext`, and some other classes from **[Mono]** to create an HTTP server that allows to accept the WebSocket handshake requests.
|
||||
|
||||
So websocket-sharp provides the `WebSocketSharp.Server.HttpServer` class.
|
||||
|
||||
You can add any WebSocket service to your `HttpServer` with the specified behavior and path to the service, by using the `HttpServer.AddWebSocketService<TBehaviorWithNew> (string)` or `HttpServer.AddWebSocketService<TBehavior> (string, Func<TBehavior>)` method.
|
||||
|
||||
```csharp
|
||||
var httpsv = new HttpServer (4649);
|
||||
httpsv.AddWebSocketService<Echo> ("/Echo");
|
||||
httpsv.AddWebSocketService<Chat> ("/Chat");
|
||||
httpsv.AddWebSocketService<Chat> ("/ChatWithNyan", () => new Chat (" Nyan!"));
|
||||
```
|
||||
|
||||
For more information, would you see **[Example3]**?
|
||||
|
||||
### WebSocket Extensions ###
|
||||
|
||||
#### Per-message Compression ####
|
||||
|
||||
websocket-sharp supports the **[Per-message Compression][compression]** extension (but doesn't support this extension with the [context take over]).
|
||||
|
||||
As a WebSocket client, if you would like to enable this extension, you should set such as the following.
|
||||
|
||||
```csharp
|
||||
ws.Compression = CompressionMethod.Deflate;
|
||||
```
|
||||
|
||||
And then your client will send the following header in the handshake request to the server.
|
||||
|
||||
Sec-WebSocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover
|
||||
|
||||
If the server accepts this extension, it will return the same header which has the corresponding value. And when your client receives it, this extension will be available.
|
||||
|
||||
#### Ignoring the extensions ####
|
||||
|
||||
As a WebSocket server, if you would like to ignore the extensions requested from a client, you should set the `WebSocketBehavior.IgnoreExtensions` property to `true` in your `WebSocketBehavior` constructor or initializing it, such as the following.
|
||||
|
||||
```csharp
|
||||
wssv.AddWebSocketService<Chat> (
|
||||
"/Chat",
|
||||
() =>
|
||||
new Chat () {
|
||||
// To ignore the extensions requested from a client.
|
||||
IgnoreExtensions = true
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
If it's set to `true`, the service will not return the **Sec-WebSocket-Extensions** header in its handshake response.
|
||||
|
||||
I think this is useful when you get something error in connecting the server and exclude the extensions as a cause of the error.
|
||||
|
||||
### Secure Connection ###
|
||||
|
||||
websocket-sharp supports the **Secure Connection** with **SSL/TLS**.
|
||||
|
||||
As a **WebSocket Client**, you should create a new instance of the `WebSocket` class with the **wss** scheme WebSocket URL.
|
||||
|
||||
```csharp
|
||||
using (var ws = new WebSocket ("wss://example.com")) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
And if you would like to use the custom validation for the server certificate, you should set the `WebSocket.SslConfiguration.ServerCertificateValidationCallback` property.
|
||||
|
||||
```csharp
|
||||
ws.SslConfiguration.ServerCertificateValidationCallback =
|
||||
(sender, certificate, chain, sslPolicyErrors) => {
|
||||
// Do something to validate the server certificate.
|
||||
...
|
||||
|
||||
return true; // If the server certificate is valid.
|
||||
};
|
||||
```
|
||||
|
||||
If you set this property to nothing, the validation does nothing with the server certificate, and returns `true`.
|
||||
|
||||
As a **WebSocket Server**, you should create a new instance of the `WebSocketServer` or `HttpServer` class with some settings for secure connection, such as the following.
|
||||
|
||||
```csharp
|
||||
var wssv = new WebSocketServer (5963, true);
|
||||
wssv.SslConfiguration.ServerCertificate =
|
||||
new X509Certificate2 ("/path/to/cert.pfx", "password for cert.pfx");
|
||||
```
|
||||
|
||||
### HTTP Authentication ###
|
||||
|
||||
websocket-sharp supports the **[HTTP Authentication (Basic/Digest)][rfc2617]**.
|
||||
|
||||
As a **WebSocket Client**, you should set a pair of user name and password for the HTTP authentication, by using the `WebSocket.SetCredentials (string, string, bool)` method before connecting.
|
||||
|
||||
```csharp
|
||||
ws.SetCredentials ("nobita", "password", preAuth);
|
||||
```
|
||||
|
||||
If `preAuth` is `true`, the `WebSocket` sends the Basic authentication credentials with the first handshake request to the server.
|
||||
|
||||
Or if `preAuth` is `false`, the `WebSocket` sends either the Basic or Digest (determined by the unauthorized response to the first handshake request) authentication credentials with the second handshake request to the server.
|
||||
|
||||
As a **WebSocket Server**, you should set an HTTP authentication scheme, a realm, and any function to find the user credentials before starting, such as the following.
|
||||
|
||||
```csharp
|
||||
wssv.AuthenticationSchemes = AuthenticationSchemes.Basic;
|
||||
wssv.Realm = "WebSocket Test";
|
||||
wssv.UserCredentialsFinder = id => {
|
||||
var name = id.Name;
|
||||
|
||||
// Return user name, password, and roles.
|
||||
return name == "nobita"
|
||||
? new NetworkCredential (name, "password", "gunfighter")
|
||||
: null; // If the user credentials aren't found.
|
||||
};
|
||||
```
|
||||
|
||||
If you would like to provide the Digest authentication, you should set such as the following.
|
||||
|
||||
```csharp
|
||||
wssv.AuthenticationSchemes = AuthenticationSchemes.Digest;
|
||||
```
|
||||
|
||||
### Query String, Origin header and Cookies ###
|
||||
|
||||
As a **WebSocket Client**, if you would like to send the **Query String** with the handshake request to the server, you should create a new instance of the `WebSocket` class with the WebSocket URL that includes the [Query] string parameters.
|
||||
|
||||
```csharp
|
||||
using (var ws = new WebSocket ("ws://example.com/?name=nobita")) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
And if you would like to send the **Origin** header with the handshake request to the server, you should set the `WebSocket.Origin` property to an allowable value as the [Origin] header before connecting, such as the following.
|
||||
|
||||
```csharp
|
||||
ws.Origin = "http://example.com";
|
||||
```
|
||||
|
||||
And also if you would like to send the **Cookies** with the handshake request to the server, you should set any cookie by using the `WebSocket.SetCookie (WebSocketSharp.Net.Cookie)` method before connecting, such as the following.
|
||||
|
||||
```csharp
|
||||
ws.SetCookie (new Cookie ("name", "nobita"));
|
||||
```
|
||||
|
||||
As a **WebSocket Server**, if you would like to get the **Query String** included in a handshake request, you should access the `WebSocketBehavior.Context.QueryString` property, such as the following.
|
||||
|
||||
```csharp
|
||||
public class Chat : WebSocketBehavior
|
||||
{
|
||||
private string _name;
|
||||
...
|
||||
|
||||
protected override void OnOpen ()
|
||||
{
|
||||
_name = Context.QueryString["name"];
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
And if you would like to validate the **Origin** header, **Cookies**, or both included in a handshake request, you should set each validation with your `WebSocketBehavior`, for example, by using the `AddWebSocketService<TBehavior> (string, Func<TBehavior>)` method with initializing, such as the following.
|
||||
|
||||
```csharp
|
||||
wssv.AddWebSocketService<Chat> (
|
||||
"/Chat",
|
||||
() =>
|
||||
new Chat () {
|
||||
OriginValidator = val => {
|
||||
// Check the value of the Origin header, and return true if valid.
|
||||
Uri origin;
|
||||
return !val.IsNullOrEmpty ()
|
||||
&& Uri.TryCreate (val, UriKind.Absolute, out origin)
|
||||
&& origin.Host == "example.com";
|
||||
},
|
||||
CookiesValidator = (req, res) => {
|
||||
// Check the cookies in 'req', and set the cookies to send to
|
||||
// the client with 'res' if necessary.
|
||||
foreach (Cookie cookie in req) {
|
||||
cookie.Expired = true;
|
||||
res.Add (cookie);
|
||||
}
|
||||
|
||||
return true; // If valid.
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
And also if you would like to get each value of the Origin header and cookies, you should access each of the `WebSocketBehavior.Context.Origin` and `WebSocketBehavior.Context.CookieCollection` properties.
|
||||
|
||||
### Connecting through the HTTP Proxy server ###
|
||||
|
||||
websocket-sharp supports to connect through the **HTTP Proxy** server.
|
||||
|
||||
If you would like to connect to a WebSocket server through the HTTP proxy server, you should set the proxy server URL, and if necessary, a pair of user name and password for the proxy server authentication (Basic/Digest), by using the `WebSocket.SetProxy (string, string, string)` method before connecting.
|
||||
|
||||
```csharp
|
||||
var ws = new WebSocket ("ws://example.com");
|
||||
ws.SetProxy ("http://localhost:3128", "nobita", "password");
|
||||
```
|
||||
|
||||
I have tested this with **[Squid]**. It's necessary to disable the following configuration option in **squid.conf** (e.g. `/etc/squid/squid.conf`).
|
||||
|
||||
```
|
||||
# Deny CONNECT to other than SSL ports
|
||||
#http_access deny CONNECT !SSL_ports
|
||||
```
|
||||
|
||||
### Logging ###
|
||||
|
||||
The `WebSocket` class has the own logging function.
|
||||
|
||||
You can use it with the `WebSocket.Log` property (returns a `WebSocketSharp.Logger`).
|
||||
|
||||
So if you would like to change the current logging level (`WebSocketSharp.LogLevel.Error` as the default), you should set the `WebSocket.Log.Level` property to any of the `LogLevel` enum values.
|
||||
|
||||
```csharp
|
||||
ws.Log.Level = LogLevel.Debug;
|
||||
```
|
||||
|
||||
The above means a log with lower than `LogLevel.Debug` cannot be outputted.
|
||||
|
||||
And if you would like to output a log, you should use any of the output methods. The following outputs a log with `LogLevel.Debug`.
|
||||
|
||||
```csharp
|
||||
ws.Log.Debug ("This is a debug message.");
|
||||
```
|
||||
|
||||
The `WebSocketServer` and `HttpServer` classes have the same logging function.
|
||||
|
||||
## Examples ##
|
||||
|
||||
Examples using websocket-sharp.
|
||||
|
||||
### Example ###
|
||||
|
||||
**[Example]** connects to the **[Echo server]** with the WebSocket.
|
||||
|
||||
### Example2 ###
|
||||
|
||||
**[Example2]** starts a WebSocket server.
|
||||
|
||||
### Example3 ###
|
||||
|
||||
**[Example3]** starts an HTTP server that allows to accept the WebSocket handshake requests.
|
||||
|
||||
Would you access to [http://localhost:4649](http://localhost:4649) to do **WebSocket Echo Test** with your web browser while Example3 is running?
|
||||
|
||||
## Supported WebSocket Specifications ##
|
||||
|
||||
websocket-sharp supports **[RFC 6455][rfc6455]**, and it's based on the following WebSocket references:
|
||||
|
||||
- **[The WebSocket Protocol][rfc6455]**
|
||||
- **[The WebSocket API][api]**
|
||||
- **[Compression Extensions for WebSocket][compression]**
|
||||
|
||||
Thanks for translating to japanese.
|
||||
|
||||
- **[The WebSocket Protocol 日本語訳][rfc6455_ja]**
|
||||
- **[The WebSocket API 日本語訳][api_ja]**
|
||||
|
||||
## License ##
|
||||
|
||||
websocket-sharp is provided under **[The MIT License]**.
|
||||
|
||||
|
||||
[Echo server]: http://www.websocket.org/echo.html
|
||||
[Example]: https://github.com/sta/websocket-sharp/tree/master/Example
|
||||
[Example2]: https://github.com/sta/websocket-sharp/tree/master/Example2
|
||||
[Example3]: https://github.com/sta/websocket-sharp/tree/master/Example3
|
||||
[Mono]: http://www.mono-project.com
|
||||
[MonoDevelop]: http://monodevelop.com
|
||||
[NuGet Gallery]: http://www.nuget.org
|
||||
[NuGet Gallery: websocket-sharp]: http://www.nuget.org/packages/WebSocketSharp
|
||||
[Origin]: http://tools.ietf.org/html/rfc6454#section-7
|
||||
[Query]: http://tools.ietf.org/html/rfc3986#section-3.4
|
||||
[Security Sandbox of the Webplayer]: http://docs.unity3d.com/Manual/SecuritySandbox.html
|
||||
[Squid]: http://www.squid-cache.org
|
||||
[The MIT License]: https://raw.github.com/sta/websocket-sharp/master/LICENSE.txt
|
||||
[Unity]: http://unity3d.com
|
||||
[WebGL Networking]: http://docs.unity3d.com/Manual/webgl-networking.html
|
||||
[WebSocket-Sharp for Unity]: http://u3d.as/content/sta-blockhead/websocket-sharp-for-unity
|
||||
[api]: http://www.w3.org/TR/websockets
|
||||
[api_ja]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html
|
||||
[compression]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19
|
||||
[context take over]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-19#section-8.1.1
|
||||
[rfc2617]: http://tools.ietf.org/html/rfc2617
|
||||
[rfc6455]: http://tools.ietf.org/html/rfc6455
|
||||
[rfc6455_ja]: http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user