Supports RFC 6455

This commit is contained in:
sta 2012-07-31 10:36:52 +09:00
parent fc6ee2db12
commit 118e0015d5
63 changed files with 2857 additions and 646 deletions

View File

@ -4,12 +4,12 @@ using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("wsclient1")]
[assembly: AssemblyTitle("Example")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyCopyright("sta")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

127
Example/Program.cs Normal file
View File

@ -0,0 +1,127 @@
#if NOTIFY
using Notifications;
#endif
using System;
using System.Collections;
using System.Threading;
using WebSocketSharp;
namespace Example
{
public struct NfMessage
{
public string Summary;
public string Body;
public string Icon;
}
public class ThreadState
{
public bool Enabled { get; set; }
public AutoResetEvent Notification { get; private set; }
public ThreadState()
{
Enabled = true;
Notification = new AutoResetEvent(false);
}
}
public class Program
{
private static Queue _msgQ = Queue.Synchronized(new Queue());
private static void enNfMessage(string summary, string body, string icon)
{
var msg = new NfMessage
{
Summary = summary,
Body = body,
Icon = icon
};
_msgQ.Enqueue(msg);
}
public static void Main(string[] args)
{
ThreadState ts = new ThreadState();
WaitCallback notifyMsg = state =>
{
while (ts.Enabled)
{
Thread.Sleep(500);
if (_msgQ.Count > 0)
{
NfMessage msg = (NfMessage)_msgQ.Dequeue();
#if NOTIFY
Notification nf = new Notification(msg.Summary,
msg.Body,
msg.Icon);
nf.AddHint("append", "allowed");
nf.Show();
#else
Console.WriteLine("{0}: {1}", msg.Summary, msg.Body);
#endif
}
}
ts.Notification.Set();
};
ThreadPool.QueueUserWorkItem(notifyMsg);
using (WebSocket ws = new WebSocket("ws://echo.websocket.org", "echo"))
//using (WebSocket ws = new WebSocket("wss://echo.websocket.org", "echo"))
{
ws.OnOpen += (sender, e) =>
{
ws.Send("Hi, all!");
};
ws.OnMessage += (sender, e) =>
{
enNfMessage("[WebSocket] Message", e.Data, "notification-message-im");
};
ws.OnError += (sender, e) =>
{
enNfMessage("[WebSocket] Error", e.Data, "notification-message-im");
};
ws.OnClose += (sender, e) =>
{
enNfMessage(
String.Format("[WebSocket] Close({0}:{1})", (ushort)e.Code, e.Code),
e.Reason,
"notification-message-im");
};
ws.Connect();
Thread.Sleep(500);
Console.WriteLine("\nType \"exit\" to exit.\n");
string data;
while (true)
{
Thread.Sleep(500);
Console.Write("> ");
data = Console.ReadLine();
if (data == "exit")
{
break;
}
ws.Send(data);
}
}
ts.Enabled = false;
ts.Notification.WaitOne();
}
}
}

View File

@ -4,12 +4,12 @@ using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("wsclient")]
[assembly: AssemblyTitle("Example1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyCopyright("sta")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

318
Example1/AudioStreamer.cs Normal file
View File

@ -0,0 +1,318 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
#if NOTIFY
using Notifications;
#endif
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Frame;
namespace Example
{
public struct NfMessage
{
public string Summary;
public string Body;
public string Icon;
}
public class AudioMessage
{
public uint user_id;
public byte ch_num;
public uint buffer_length;
public float[,] buffer_array;
}
public class TextMessage
{
public uint? user_id;
public string name;
public string type;
public string message;
}
public class ThreadState
{
public bool Enabled { get; set; }
public AutoResetEvent Notification { get; private set; }
public ThreadState()
{
Enabled = true;
Notification = new AutoResetEvent(false);
}
}
public class AudioStreamer : IDisposable
{
private Dictionary<uint, Queue> _audioBox;
private Queue _msgQ;
private string _name;
private WaitCallback _notifyMsg;
private ThreadState _notifyMsgState;
private TimerCallback _sendHeartbeat;
private Timer _heartbeatTimer;
private uint? _user_id;
private WebSocket _ws;
public AudioStreamer(string url)
{
_ws = new WebSocket(url);
_msgQ = Queue.Synchronized(new Queue());
_audioBox = new Dictionary<uint, Queue>();
_user_id = null;
configure();
}
private void configure()
{
_ws.OnOpen += (sender, e) =>
{
var msg = createTextMessage("connection", String.Empty);
_ws.Send(msg);
};
_ws.OnMessage += (sender, e) =>
{
switch (e.Type)
{
case Opcode.TEXT:
var msg = parseTextMessage(e.Data);
_msgQ.Enqueue(msg);
break;
case Opcode.BINARY:
var audioMsg = parseAudioMessage(e.RawData);
if (audioMsg.user_id == _user_id) goto default;
if (_audioBox.ContainsKey(audioMsg.user_id))
{
_audioBox[audioMsg.user_id].Enqueue(audioMsg.buffer_array);
}
else
{
var q = Queue.Synchronized(new Queue());
q.Enqueue(audioMsg.buffer_array);
_audioBox.Add(audioMsg.user_id, q);
}
break;
default:
break;
}
};
_ws.OnError += (sender, e) =>
{
enNfMessage("[AudioStreamer] error", "WS Error: " + e.Data, "notification-message-im");
};
_ws.OnClose += (sender, e) =>
{
enNfMessage
(
"[AudioStreamer] disconnect",
String.Format("WS Close({0}:{1}): {2}", (ushort)e.Code, e.Code, e.Reason),
"notification-message-im"
);
};
_notifyMsgState = new ThreadState();
_notifyMsg = (state) =>
{
while (_notifyMsgState.Enabled)
{
Thread.Sleep(500);
if (_msgQ.Count > 0)
{
NfMessage msg = (NfMessage)_msgQ.Dequeue();
#if NOTIFY
Notification nf = new Notification(msg.Summary,
msg.Body,
msg.Icon);
nf.AddHint("append", "allowed");
nf.Show();
#else
Console.WriteLine("{0}: {1}", msg.Summary, msg.Body);
#endif
}
}
_notifyMsgState.Notification.Set();
};
_sendHeartbeat = (state) =>
{
var msg = createTextMessage("heartbeat", String.Empty);
_ws.Send(msg);
};
}
private byte[] createAudioMessage(float[,] buffer_array)
{
List<byte> msg = new List<byte>();
uint user_id = (uint)_user_id;
int ch_num = buffer_array.GetLength(0);
int buffer_length = buffer_array.GetLength(1);
msg.AddRange(user_id.ToBytes(ByteOrder.BIG));
msg.Add((byte)ch_num);
msg.AddRange(((uint)buffer_length).ToBytes(ByteOrder.BIG));
ch_num.Times(i =>
{
buffer_length.Times(j =>
{
msg.AddRange(buffer_array[i, j].ToBytes(ByteOrder.BIG));
});
});
return msg.ToArray();
}
private string createTextMessage(string type, string message)
{
var msg = new TextMessage
{
user_id = _user_id,
name = _name,
type = type,
message = message
};
return JsonConvert.SerializeObject(msg);
}
private AudioMessage parseAudioMessage(byte[] data)
{
uint user_id = data.SubArray(0, 4).To<uint>(ByteOrder.BIG);
byte ch_num = data.SubArray(4, 1)[0];
uint buffer_length = data.SubArray(5, 4).To<uint>(ByteOrder.BIG);
float[,] buffer_array = new float[ch_num, buffer_length];
int offset = 9;
ch_num.Times(i =>
{
buffer_length.Times(j =>
{
buffer_array[i, j] = data.SubArray(offset, 4).To<float>(ByteOrder.BIG);
offset += 4;
});
});
return new AudioMessage
{
user_id = user_id,
ch_num = ch_num,
buffer_length = buffer_length,
buffer_array = buffer_array
};
}
private NfMessage parseTextMessage(string data)
{
JObject msg = JObject.Parse(data);
uint user_id = (uint)msg["user_id"];
string name = (string)msg["name"];
string type = (string)msg["type"];
string message;
switch (type)
{
case "connection":
JArray users = (JArray)msg["message"];
StringBuilder sb = new StringBuilder("Now keeping connection\n");
foreach (JToken user in users)
{
sb.AppendFormat("user_id: {0} name: {1}\n", (uint)user["user_id"], (string)user["name"]);
}
message = sb.ToString().TrimEnd('\n');
break;
case "connected":
_user_id = user_id;
message = String.Format("user_id: {0} name: {1}", user_id, name);
break;
case "message":
message = String.Format("{0}: {1}", name, (string)msg["message"]);
break;
case "start_music":
message = String.Format("{0}: Started playing music!", name);
break;
default:
message = "Received unknown type message: " + type;
break;
}
return new NfMessage
{
Summary = String.Format("[AudioStreamer] {0}", type),
Body = message,
Icon = "notification-message-im"
};
}
private void enNfMessage(string summary, string body, string icon)
{
var msg = new NfMessage
{
Summary = summary,
Body = body,
Icon = icon
};
_msgQ.Enqueue(msg);
}
public void Connect()
{
string name;
do
{
Console.Write("Your name > ");
name = Console.ReadLine();
}
while (name == String.Empty);
_name = name;
_ws.Connect();
ThreadPool.QueueUserWorkItem(_notifyMsg);
_heartbeatTimer = new Timer(_sendHeartbeat, null, 30 * 1000, 30 * 1000);
}
public void Disconnect()
{
var wait = new AutoResetEvent(false);
_heartbeatTimer.Dispose(wait);
wait.WaitOne();
_ws.Close();
_notifyMsgState.Enabled = false;
_notifyMsgState.Notification.WaitOne();
}
public void Dispose()
{
Disconnect();
}
public void Write(string data)
{
var msg = createTextMessage("message", data);
_ws.Send(msg);
}
public void Write(FileInfo file)
{
throw new NotImplementedException();
}
}
}

View File

@ -5,10 +5,10 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}</ProjectGuid>
<ProjectGuid>{390E2568-57B7-4D17-91E5-C29336368CCF}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>WsClient</RootNamespace>
<AssemblyName>wsclient</AssemblyName>
<RootNamespace>Example</RootNamespace>
<AssemblyName>example1</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -16,7 +16,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
@ -34,7 +34,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug_Ubuntu</OutputPath>
<DefineConstants>DEBUG,NOTIFY</DefineConstants>
<DefineConstants>DEBUG;NOTIFY</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
@ -43,26 +43,31 @@
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release_Ubuntu</OutputPath>
<DefineConstants>NOTIFY</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<DefineConstants>NOTIFY</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
<Private>False</Private>
<Package>notify-sharp</Package>
</Reference>
<Reference Include="Newtonsoft.Json, Version=3.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="wsclient.cs" />
<Compile Include="AudioStreamer.cs" />
<Compile Include="Program.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
<Name>websocket-sharp</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

35
Example1/Program.cs Normal file
View File

@ -0,0 +1,35 @@
using System;
using System.Threading;
namespace Example
{
public class Program
{
public static void Main(string[] args)
{
//using (AudioStreamer streamer = new AudioStreamer("ws://localhost:3000/socket"))
using (AudioStreamer streamer = new AudioStreamer("ws://agektmr.node-ninja.com:3000/socket"))
{
streamer.Connect();
Thread.Sleep(500);
Console.WriteLine("\nType \"exit\" to exit.\n");
string data;
while (true)
{
Thread.Sleep(500);
Console.Write("> ");
data = Console.ReadLine();
if (data == "exit")
{
break;
}
streamer.Write(data);
}
}
}
}
}

167
README.md
View File

@ -1,8 +1,171 @@
# websocket-sharp #
A C# implementation of a WebSocket protocol client.
**websocket-sharp** is a C# implementation of a WebSocket protocol client.
## Usage ##
Please refer to wsclient/wsclient.cs.
### Step 1 ###
Required namespaces.
using WebSocketSharp;
using WebSocketSharp.Frame;
In `WebSocketSharp` namespace `WebSocket` class exists, in `WebSocketSharp.Frame` namespace WebSocket data frame resources (e.g. `WsFrame` class) exist.
### Step 2 ###
Creating instance of `WebSocket` class.
using (WebSocket ws = new WebSocket("ws://example.com"))
{
...
}
So `WebSocket` class inherits `IDisposable` interface, you can use `using` statement.
### Step 3 ###
Setting of `WebSocket` event handlers.
#### WebSocket.OnOpen event ####
`WebSocket.OnOpen` event is emitted immediately after WebSocket connection has been established.
ws.OnOpen += (sender, e) =>
{
...
};
So `e` has come across as `EventArgs.Empty`, there is no operation on `e`.
#### WebSocket.OnMessage event ####
`WebSocket.OnMessage` event is emitted each time WebSocket data frame is received.
ws.OnMessage += (sender, e) =>
{
...
};
So **type** of received WebSocket data frame is stored in `e.Type` (`WebSocketSharp.MessageEventArgs.Type`, its type is `WebSocketSharp.Frame.Opcode`), you check it out and you determine which item you should operate.
switch (e.Type)
{
case Opcode.TEXT:
...
break;
case Opcode.BINARY:
...
break;
default:
break;
}
If `e.Type` is `Opcode.TEXT`, you operate `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, its type is `string`).
if `e.Type` is `Opcode.BINARY`, you operate `e.RawData` (`WebSocketSharp.MessageEventArgs.RawData`, its type is `byte[]`).
#### WebSocket.OnError event ####
`WebSocket.OnError` event is emitted when some error is occurred.
ws.OnError += (sender, e) =>
{
...
};
So error message is stored in `e.Data` (`WebSocketSharp.MessageEventArgs.Data`, its type is `string`) , you operate it.
#### WebSocket.OnClose event ####
`WebSocket.OnClose` event is emitted when WebSocket connection is closed.
ws.OnClose += (sender, e) =>
{
...
};
So close status code is stored in `e.Code` (`WebSocketSharp.CloseEventArgs.Code`, its type is `WebSocketSharp.Frame.CloseStatusCode`) and reason of close is stored in `e.Reason` (`WebSocketSharp.CloseEventArgs.Reason`, its type is `string`), you operate them.
### Step 4 ###
Connecting to server using WebSocket.
ws.Connect();
### Step 5 ###
Sending data.
ws.Send(data);
`WebSocket.Send` method is overloaded.
data types are `string`, `byte[]` and `FileInfo` class.
### Step 6 ###
Closing WebSocket connection.
ws.Close(code, reason);
If you want to close WebSocket connection explicitly, you can use `Close` method.
Type of `code` is `WebSocketSharp.Frame.CloseStatusCode`, type of `reason` is `string`.
`WebSocket.Close` method is overloaded (In addition `Close()` and `Close(code)` exist).
## Examples ##
Examples of using **websocket-sharp**.
### Example ###
[Example] connects to the [Echo server] using the WebSocket.
### Example1 ###
[Example1] connects to the [Audio Data delivery server] using the WebSocket ([Example1] is only implemented a chat feature, still unfinished).
[Example1] uses [Json.NET].
## Supported WebSocket Protocol ##
**websocket-sharp** supports **[RFC 6455]**.
- @**[branch: hybi-00]** supports older draft-ietf-hybi-thewebsocketprotocol-00 (**[hybi-00]**).
- @**[branch: draft75]** supports even more old draft-hixie-thewebsocketprotocol-75 (**[hixie-75]**).
## Reference ##
- **[The WebSocket Protocol]**
- **[The WebSocket API]**
Thx for translating to japanese.
- **[The WebSocket Protocol 日本語訳]**
- **[The WebSocket API 日本語訳]**
## License ##
Copyright &copy; 2010 - 2012 sta.blockhead
Licensed under the **[MIT License]**.
[Audio Data delivery server]: http://agektmr.node-ninja.com:3000/
[branch: draft75]: https://github.com/sta/websocket-sharp/tree/draft75
[branch: hybi-00]: https://github.com/sta/websocket-sharp/tree/hybi-00
[Echo server]: http://www.websocket.org/echo.html
[Example]: https://github.com/sta/websocket-sharp/tree/master/Example
[Example1]: https://github.com/sta/websocket-sharp/tree/master/Example1
[hixie-75]: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
[hybi-00]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
[Json.NET]: http://james.newtonking.com/projects/json-net.aspx
[MIT License]: http://www.opensource.org/licenses/mit-license.php
[RFC 6455]: http://tools.ietf.org/html/rfc6455
[The WebSocket API]: http://dev.w3.org/html5/websockets
[The WebSocket API 日本語訳]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html
[The WebSocket Protocol]: http://tools.ietf.org/html/rfc6455
[The WebSocket Protocol 日本語訳]: http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html

View File

@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient", "wsclient\wsclient.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsclient1", "wsclient1\wsclient1.csproj", "{B0B609B7-A81C-46B0-A9B8-82E9716D355B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example1", "Example1\Example1.csproj", "{390E2568-57B7-4D17-91E5-C29336368CCF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -15,6 +15,14 @@ Global
Release_Ubuntu|Any CPU = Release_Ubuntu|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{390E2568-57B7-4D17-91E5-C29336368CCF}.Release|Any CPU.Build.0 = Release|Any CPU
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -23,14 +31,6 @@ Global
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.ActiveCfg = Release|Any CPU
{52805AEC-EFB1-4F42-BB8E-3ED4E692C568}.Release|Any CPU.Build.0 = Release|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release_Ubuntu|Any CPU.ActiveCfg = Release_Ubuntu|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release_Ubuntu|Any CPU.Build.0 = Release_Ubuntu|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0B609B7-A81C-46B0-A9B8-82E9716D355B}.Release|Any CPU.Build.0 = Release|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.ActiveCfg = Debug_Ubuntu|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug_Ubuntu|Any CPU.Build.0 = Debug_Ubuntu|Any CPU
{B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU

View File

@ -1,12 +1,12 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release" ctype="Workspace" />
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs" ctype="Workbench">
<MonoDevelop.Ide.Workspace ActiveConfiguration="Release_Ubuntu" />
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs">
<Files>
<File FileName="websocket-sharp/WebSocket.cs" Line="80" Column="19" />
<File FileName="websocket-sharp/WebSocket.cs" Line="217" Column="41" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches ctype="PinnedWatchStore" />
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
</Properties>

View File

@ -17,7 +17,7 @@ using System.Runtime.CompilerServices;
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.0.*")]
[assembly: AssemblyVersion("1.0.1.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.

View File

@ -0,0 +1,38 @@
#region MIT License
/**
* ByteOrder.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp
{
public enum ByteOrder : byte
{
LITTLE = 0x0,
BIG = 0x1
}
}

View File

@ -0,0 +1,87 @@
#region MIT License
/**
* CloseEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Text;
using WebSocketSharp.Frame;
namespace WebSocketSharp
{
public class CloseEventArgs : MessageEventArgs
{
private ushort _code;
private string _reason;
private bool _wasClean;
public CloseStatusCode Code
{
get
{
return (CloseStatusCode)_code;
}
}
public string Reason
{
get
{
return _reason;
}
}
public bool WasClean
{
get
{
return _wasClean;
}
set
{
_wasClean = value;
}
}
public CloseEventArgs(PayloadData data)
: base(Opcode.CLOSE, data)
{
_code = data.ToBytes().SubArray(0, 2).To<ushort>(ByteOrder.BIG);
if (data.Length > 2)
{
var buffer = data.ToBytes().SubArray(2, (int)(data.Length - 2));
_reason = Encoding.UTF8.GetString(buffer);
}
else
{
_reason = String.Empty;
}
_wasClean = false;
}
}
}

View File

@ -4,7 +4,7 @@
*
* The MIT License
*
* Copyright (c) 2010 sta.blockhead
* Copyright (c) 2010-2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -28,19 +28,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace WebSocketSharp
{
public static class Ext
{
public static bool AreNotEqualDo(
public static bool EqualsAndSaveTo(this int value, char c, List<byte> dest)
{
byte b = (byte)value;
dest.Add(b);
return b == Convert.ToByte(c);
}
public static string GetHeaderValue(this string src, string separater)
{
int i = src.IndexOf(separater);
return src.Substring(i + 1).Trim();
}
public static bool IsHostOrder(this ByteOrder order)
{
if (BitConverter.IsLittleEndian ^ (order == ByteOrder.LITTLE))
{// true ^ false or false ^ true
return false;
}
else
{// true ^ true or false ^ false
return true;
}
}
public static bool IsNullDo<T>(this T value, Action act)
where T : class
{
if (value == null)
{
act();
return true;
}
return false;
}
public static bool NotEqualsDo(
this string expected,
string actual,
Func<string, string, string> func,
out string ret)
out string ret,
bool ignoreCase)
{
if (expected != actual)
if (String.Compare(expected, actual, ignoreCase) != 0)
{
ret = func(expected, actual);
return true;
@ -50,106 +90,226 @@ namespace WebSocketSharp
return false;
}
public static bool EqualsWithSaveTo(this int asByte, char c, List<byte> dist)
public static byte[] ReadBytes<TStream>(this TStream stream, ulong length, int bufferLength)
where TStream : System.IO.Stream
{
byte b = (byte)asByte;
dist.Add(b);
return b == Convert.ToByte(c);
}
List<byte> readData = new List<byte>();
public static uint GenerateKey(this Random rand, int space)
{
uint max = (uint)(0xffffffff / space);
ulong count = length / (ulong)bufferLength;
int remainder = (int)(length % (ulong)bufferLength);
int upper16 = (int)((max & 0xffff0000) >> 16);
int lower16 = (int)(max & 0x0000ffff);
byte[] buffer1 = new byte[bufferLength];
return ((uint)rand.Next(upper16 + 1) << 16) + (uint)rand.Next(lower16 + 1);
}
public static char GeneratePrintableASCIIwithoutSPandNum(this Random rand)
{
int ascii = rand.Next(2) == 0 ? rand.Next(33, 48) : rand.Next(58, 127);
return Convert.ToChar(ascii);
}
public static string GenerateSecKey(this Random rand, out uint key)
{
int space = rand.Next(1, 13);
int ascii = rand.Next(1, 13);
key = rand.GenerateKey(space);
long mKey = key * space;
List<char> secKey = new List<char>(mKey.ToString().ToCharArray());
int i;
ascii.Times( () =>
count.Times(() =>
{
i = rand.Next(secKey.Count + 1);
secKey.Insert(i, rand.GeneratePrintableASCIIwithoutSPandNum());
} );
stream.Read(buffer1, 0, bufferLength);
readData.AddRange(buffer1);
});
space.Times( () =>
if (remainder > 0)
{
i = rand.Next(1, secKey.Count);
secKey.Insert(i, ' ');
} );
return new String(secKey.ToArray());
}
public static byte[] InitializeWithPrintableASCII(this byte[] bytes, Random rand)
{
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)rand.Next(32, 127);
}
return bytes;
}
public static bool IsValid(this string[] response, byte[] expectedCR, byte[] actualCR, out string message)
{
string expectedCRtoHexStr = BitConverter.ToString(expectedCR);
string actualCRtoHexStr = BitConverter.ToString(actualCR);
Func<string, Func<string, string, string>> func = s =>
{
return (e, a) =>
{
#if DEBUG
Console.WriteLine("WS: Error @IsValid: Invalid {0} response.", s);
Console.WriteLine(" expected: {0}", e);
Console.WriteLine(" actual : {0}", a);
#endif
return String.Format("Invalid {0} response: {1}", s, a);
};
};
Func<string, string, string> func1 = func("handshake");
Func<string, string, string> func2 = func("challenge");
string msg;
if ("HTTP/1.1 101 WebSocket Protocol Handshake".AreNotEqualDo(response[0], func1, out msg) ||
"Upgrade: WebSocket".AreNotEqualDo(response[1], func1, out msg) ||
"Connection: Upgrade".AreNotEqualDo(response[2], func1, out msg) ||
expectedCRtoHexStr.AreNotEqualDo(actualCRtoHexStr, func2, out msg))
{
message = msg;
return false;
byte[] buffer2 = new byte[remainder];
stream.Read(buffer2, 0, remainder);
readData.AddRange(buffer2);
}
message = String.Empty;
return true;
return readData.ToArray();
}
public static void Times(this int n, Action act)
public static T[] SubArray<T>(this T[] array, int startIndex, int length)
{
for (int i = 0; i < n; i++)
if (startIndex == 0 && array.Length == length)
{
return array;
}
T[] subArray = new T[length];
Array.Copy(array, startIndex, subArray, 0, length);
return subArray;
}
public static void Times<T>(this T n, Action act)
where T : struct
{
if (typeof(T) != typeof(byte) &&
typeof(T) != typeof(Int16) &&
typeof(T) != typeof(Int32) &&
typeof(T) != typeof(Int64) &&
typeof(T) != typeof(UInt16) &&
typeof(T) != typeof(UInt32) &&
typeof(T) != typeof(UInt64))
{
throw new NotSupportedException("Not supported Struct type: " + typeof(T).ToString());
}
ulong m = (ulong)(object)n;
for (ulong i = 0; i < m; i++)
{
act();
}
}
public static void Times<T>(this T n, Action<ulong> act)
where T : struct
{
if (typeof(T) != typeof(byte) &&
typeof(T) != typeof(Int16) &&
typeof(T) != typeof(Int32) &&
typeof(T) != typeof(Int64) &&
typeof(T) != typeof(UInt16) &&
typeof(T) != typeof(UInt32) &&
typeof(T) != typeof(UInt64))
{
throw new NotSupportedException("Not supported Struct type: " + typeof(T).ToString());
}
ulong m = (ulong)(object)n;
for (ulong i = 0; i < m; i++)
{
act(i);
}
}
public static T To<T>(this byte[] src, ByteOrder srcOrder)
where T : struct
{
T dest;
byte[] buffer = src.ToHostOrder(srcOrder);
if (typeof(T) == typeof(Boolean))
{
dest = (T)(object)BitConverter.ToBoolean(buffer, 0);
}
else if (typeof(T) == typeof(Char))
{
dest = (T)(object)BitConverter.ToChar(buffer, 0);
}
else if (typeof(T) == typeof(Double))
{
dest = (T)(object)BitConverter.ToDouble(buffer, 0);
}
else if (typeof(T) == typeof(Int16))
{
dest = (T)(object)BitConverter.ToInt16(buffer, 0);
}
else if (typeof(T) == typeof(Int32))
{
dest = (T)(object)BitConverter.ToInt32(buffer, 0);
}
else if (typeof(T) == typeof(Int64))
{
dest = (T)(object)BitConverter.ToInt64(buffer, 0);
}
else if (typeof(T) == typeof(Single))
{
dest = (T)(object)BitConverter.ToSingle(buffer, 0);
}
else if (typeof(T) == typeof(UInt16))
{
dest = (T)(object)BitConverter.ToUInt16(buffer, 0);
}
else if (typeof(T) == typeof(UInt32))
{
dest = (T)(object)BitConverter.ToUInt32(buffer, 0);
}
else if (typeof(T) == typeof(UInt64))
{
dest = (T)(object)BitConverter.ToUInt64(buffer, 0);
}
else
{
dest = default(T);
}
return dest;
}
public static byte[] ToBytes<T>(this T value, ByteOrder order)
where T : struct
{
byte[] buffer;
if (typeof(T) == typeof(Boolean))
{
buffer = BitConverter.GetBytes((Boolean)(object)value);
}
else if (typeof(T) == typeof(Char))
{
buffer = BitConverter.GetBytes((Char)(object)value);
}
else if (typeof(T) == typeof(Double))
{
buffer = BitConverter.GetBytes((Double)(object)value);
}
else if (typeof(T) == typeof(Int16))
{
buffer = BitConverter.GetBytes((Int16)(object)value);
}
else if (typeof(T) == typeof(Int32))
{
buffer = BitConverter.GetBytes((Int32)(object)value);
}
else if (typeof(T) == typeof(Int64))
{
buffer = BitConverter.GetBytes((Int64)(object)value);
}
else if (typeof(T) == typeof(Single))
{
buffer = BitConverter.GetBytes((Single)(object)value);
}
else if (typeof(T) == typeof(UInt16))
{
buffer = BitConverter.GetBytes((UInt16)(object)value);
}
else if (typeof(T) == typeof(UInt32))
{
buffer = BitConverter.GetBytes((UInt32)(object)value);
}
else if (typeof(T) == typeof(UInt64))
{
buffer = BitConverter.GetBytes((UInt64)(object)value);
}
else
{
buffer = new byte[]{};
}
return order.IsHostOrder()
? buffer
: buffer.Reverse().ToArray();
}
public static byte[] ToHostOrder(this byte[] src, ByteOrder srcOrder)
{
byte[] buffer = new byte[src.Length];
src.CopyTo(buffer, 0);
return srcOrder.IsHostOrder()
? buffer
: buffer.Reverse().ToArray();
}
public static string ToString<T>(this T[] array, string separater)
{
int len;
StringBuilder sb;
len = array.Length;
if (len == 0)
{
return String.Empty;
}
sb = new StringBuilder();
for (int i = 0; i < len - 1; i++)
{
sb.AppendFormat("{0}{1}", array[i].ToString(), separater);
}
sb.Append(array[len - 1].ToString());
return sb.ToString();
}
}
}

View File

@ -0,0 +1,59 @@
#region MIT License
/**
* CloseStatusCode.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Frame
{
public enum CloseStatusCode : ushort
{
/*
* Close Status Code
*
* Defined Status Codes: http://tools.ietf.org/html/rfc6455#section-7.4.1
*
* "Reserved value" MUST NOT be set as a status code in a Close control frame by an endpoint.
* It is designated for use in applications expecting a status code to indicate that connection
* was closed due to a system grounds.
*
*/
NORMAL = 1000, // Normal closure.
AWAY = 1001, // A Server going down or a browser having navigated away from a page.
PROTOCOL_ERROR = 1002, // Terminating the connection due to a protocol error.
INCORRECT_DATA = 1003, // Received a type of data it cannot accept.
UNDEFINED = 1004, // Reserved value. Still undefined.
NO_STATUS_CODE = 1005, // Reserved value.
ABNORMAL = 1006, // Reserved value. Connection was closed abnormally.
INCONSISTENT_DATA = 1007, // Received data within a message that was not consistent with the type of the message.
POLICY_VIOLATION = 1008, // Received a message that violates its policy.
TOO_BIG = 1009, // Received a message that is too big.
IGNORE_EXTENSION = 1010, // Server ignored negotiated extensions.
SERVER_ERROR = 1011, // Server encountered an unexpected condition.
HANDSHAKE_FAILURE = 1015 // Reserved value. Failure to establish a connection.
}
}

View File

@ -0,0 +1,38 @@
#region MIT License
/**
* Fin.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Frame
{
public enum Fin : byte
{
MORE = 0x0,
FINAL = 0x1
}
}

View File

@ -0,0 +1,38 @@
#region MIT License
/**
* Mask.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Frame
{
public enum Mask : byte
{
UNMASK = 0x0,
MASK = 0x1
}
}

View File

@ -0,0 +1,43 @@
#region MIT License
/**
* Opcode.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Frame
{
[Flags]
public enum Opcode : byte
{
CONT = 0x0,
TEXT = 0x1,
BINARY = 0x2,
CLOSE = 0x8,
PING = 0x9,
PONG = 0xa
}
}

View File

@ -0,0 +1,184 @@
#region MIT License
/**
* PayloadData.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebSocketSharp.Frame
{
public class PayloadData : IEnumerable<byte>
{
#region Public Static Fields
public static readonly ulong MaxLength;
#endregion
#region Properties
public byte[] ExtensionData { get; private set; }
public byte[] ApplicationData { get; private set; }
public bool IsMasked { get; private set; }
public ulong Length
{
get
{
return (ulong)(ExtensionData.LongLength + ApplicationData.LongLength);
}
}
#endregion
#region Static Constructor
static PayloadData()
{
MaxLength = long.MaxValue;
}
#endregion
#region Public Constructors
public PayloadData(string appData)
: this(Encoding.UTF8.GetBytes(appData))
{
}
public PayloadData(byte[] appData)
: this(new byte[]{}, appData)
{
}
public PayloadData(byte[] appData, bool masked)
: this(new byte[]{}, appData, masked)
{
}
public PayloadData(byte[] extData, byte[] appData)
: this(extData, appData, false)
{
}
public PayloadData(byte[] extData, byte[] appData, bool masked)
{
Func<string, Action> func = s => () =>
{
string message = String.Format("{0} must not be null.", s);
throw new ArgumentNullException(message);
};
extData.IsNullDo(func("extData"));
appData.IsNullDo(func("appData"));
if ((ulong)extData.LongLength + (ulong)appData.LongLength > MaxLength)
{
throw new ArgumentOutOfRangeException("Plus extData length and appData lenght must be less than MaxLength.");
}
ExtensionData = extData;
ApplicationData = appData;
IsMasked = masked;
}
#endregion
#region Private Methods
private void mask(byte[] src, byte[] key)
{
if (key.Length != 4)
{
throw new ArgumentOutOfRangeException("key length must be 4.");
}
for (long i = 0; i < src.LongLength; i++)
{
src[i] = (byte)(src[i] ^ key[i % 4]);
}
}
#endregion
#region Public Methods
public IEnumerator<byte> GetEnumerator()
{
foreach (byte b in ExtensionData)
{
yield return b;
}
foreach (byte b in ApplicationData)
{
yield return b;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Mask(byte[] maskingKey)
{
if (ExtensionData.LongLength > 0)
{
mask(ExtensionData, maskingKey);
}
if (ApplicationData.LongLength > 0)
{
mask(ApplicationData, maskingKey);
}
IsMasked = !IsMasked;
}
public byte[] ToBytes()
{
if (ExtensionData.LongLength > 0)
{
return ExtensionData.Concat(ApplicationData).ToArray();
}
else
{
return ApplicationData;
}
}
public override string ToString()
{
return BitConverter.ToString(ToBytes());
}
#endregion
}
}

View File

@ -0,0 +1,38 @@
#region MIT License
/**
* Rsv.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
namespace WebSocketSharp.Frame
{
public enum Rsv : byte
{
OFF = 0x0,
ON = 0x1
}
}

View File

@ -0,0 +1,461 @@
#region MIT License
/**
* WsFrame.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
namespace WebSocketSharp.Frame
{
public class WsFrame : IEnumerable<byte>
{
#region Private Static Fields
private static readonly int _readBufferLen;
#endregion
#region Properties
public Fin Fin { get; private set; }
public Rsv Rsv1 { get; private set; }
public Rsv Rsv2 { get; private set; }
public Rsv Rsv3 { get; private set; }
public Opcode Opcode { get; private set; }
public Mask Masked { get; private set; }
public byte PayloadLen { get; private set; }
public byte[] ExtPayloadLen { get; private set; }
public byte[] MaskingKey { get; private set; }
public PayloadData PayloadData { get; private set; }
public ulong Length
{
get
{
return 2 + (ulong)(ExtPayloadLen.Length + MaskingKey.Length) + PayloadLength;
}
}
public ulong PayloadLength
{
get
{
return PayloadData.Length;
}
}
#endregion
#region Static Constructor
static WsFrame()
{
_readBufferLen = 1024;
}
#endregion
#region Private Constructors
private WsFrame()
{
Rsv1 = Rsv.OFF;
Rsv2 = Rsv.OFF;
Rsv3 = Rsv.OFF;
ExtPayloadLen = new byte[]{};
MaskingKey = new byte[]{};
}
#endregion
#region Public Constructors
public WsFrame(Opcode opcode, PayloadData payloadData)
: this(Fin.FINAL, opcode, payloadData)
{
}
public WsFrame(Fin fin, Opcode opcode, PayloadData payloadData)
: this(fin, opcode, Mask.MASK, payloadData)
{
}
public WsFrame(Fin fin, Opcode opcode, Mask mask, PayloadData payloadData)
: this()
{
Fin = fin;
Opcode = opcode;
Masked = mask;
ulong dataLength = payloadData.Length;
if (dataLength < 126)
{
PayloadLen = (byte)dataLength;
}
else if (dataLength < 0x010000)
{
PayloadLen = (byte)126;
ExtPayloadLen = ((ushort)dataLength).ToBytes(ByteOrder.BIG);
}
else
{
PayloadLen = (byte)127;
ExtPayloadLen = dataLength.ToBytes(ByteOrder.BIG);
}
PayloadData = payloadData;
if (Masked == Mask.MASK)
{
MaskingKey = new byte[4];
var rand = new Random();
rand.NextBytes(MaskingKey);
PayloadData.Mask(MaskingKey);
}
}
#endregion
#region Public Static Methods
public static WsFrame Parse(byte[] src)
{
return Parse(src, true);
}
public static WsFrame Parse(byte[] src, bool unmask)
{
using (MemoryStream ms = new MemoryStream(src))
{
return Parse(ms, unmask);
}
}
public static WsFrame Parse<TStream>(TStream stream)
where TStream : System.IO.Stream
{
return Parse(stream, true);
}
public static WsFrame Parse<TStream>(TStream stream, bool unmask)
where TStream : System.IO.Stream
{
Fin fin;
Rsv rsv1, rsv2, rsv3;
Opcode opcode;
Mask masked;
byte payloadLen;
byte[] extPayloadLen = new byte[]{};
byte[] maskingKey = new byte[]{};
PayloadData payloadData;
byte[] buffer1, buffer2, buffer3;
int buffer1Len = 2;
int buffer2Len = 0;
ulong buffer3Len = 0;
int maskingKeyLen = 4;
buffer1 = new byte[buffer1Len];
stream.Read(buffer1, 0, buffer1Len);
// FIN
fin = (buffer1[0] & 0x80) == 0x80
? Fin.FINAL
: Fin.MORE;
// RSV1
rsv1 = (buffer1[0] & 0x40) == 0x40
? Rsv.ON
: Rsv.OFF;
// RSV2
rsv2 = (buffer1[0] & 0x20) == 0x20
? Rsv.ON
: Rsv.OFF;
// RSV3
rsv3 = (buffer1[0] & 0x10) == 0x10
? Rsv.ON
: Rsv.OFF;
// opcode
opcode = (Opcode)(buffer1[0] & 0x0f);
// MASK
masked = (buffer1[1] & 0x80) == 0x80
? Mask.MASK
: Mask.UNMASK;
// Payload len
payloadLen = (byte)(buffer1[1] & 0x7f);
// Extended payload length
if (payloadLen <= 125)
{
buffer3Len = payloadLen;
}
else if (payloadLen == 126)
{
buffer2Len = 2;
}
else
{
buffer2Len = 8;
}
if (buffer2Len > 0)
{
buffer2 = new byte[buffer2Len];
stream.Read(buffer2, 0, buffer2Len);
extPayloadLen = buffer2;
switch (buffer2Len)
{
case 2:
buffer3Len = extPayloadLen.To<ushort>(ByteOrder.BIG);
break;
case 8:
buffer3Len = extPayloadLen.To<ulong>(ByteOrder.BIG);
break;
}
}
if (buffer3Len > PayloadData.MaxLength)
{
throw new WsReceivedTooBigMessageException();
}
// Masking-key
if (masked == Mask.MASK)
{
maskingKey = new byte[maskingKeyLen];
stream.Read(maskingKey, 0, maskingKeyLen);
}
// Payload Data
if (buffer3Len <= (ulong)_readBufferLen)
{
buffer3 = new byte[buffer3Len];
stream.Read(buffer3, 0, (int)buffer3Len);
}
else
{
buffer3 = stream.ReadBytes(buffer3Len, _readBufferLen);
}
if (masked == Mask.MASK)
{
payloadData = new PayloadData(buffer3, true);
if (unmask == true)
{
payloadData.Mask(maskingKey);
masked = Mask.UNMASK;
maskingKey = new byte[]{};
}
}
else
{
payloadData = new PayloadData(buffer3);
}
return new WsFrame
{
Fin = fin,
Rsv1 = rsv1,
Rsv2 = rsv2,
Rsv3 = rsv3,
Opcode = opcode,
Masked = masked,
PayloadLen = payloadLen,
ExtPayloadLen = extPayloadLen,
MaskingKey = maskingKey,
PayloadData = payloadData
};
}
#endregion
#region Public Methods
public IEnumerator<byte> GetEnumerator()
{
foreach (byte b in ToBytes())
{
yield return b;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Print()
{
byte[] buffer;
long count, i, j;
int countDigit, remainder;
string countFmt, extPayloadLen, headerFmt, topLineFmt, bottomLineFmt, payloadData, spFmt;
switch (ExtPayloadLen.Length)
{
case 2:
extPayloadLen = ExtPayloadLen.To<ushort>(ByteOrder.BIG).ToString();
break;
case 8:
extPayloadLen = ExtPayloadLen.To<ulong>(ByteOrder.BIG).ToString();
break;
default:
extPayloadLen = String.Empty;
break;
}
if (((Opcode.TEXT | Opcode.PING | Opcode.PONG) & Opcode) == Opcode &&
Masked == Mask.UNMASK &&
PayloadLength > 0)
{
payloadData = Encoding.UTF8.GetString(PayloadData.ToBytes());
}
else
{
payloadData = BitConverter.ToString(PayloadData.ToBytes());
}
headerFmt = @"
WsFrame:
FIN={0}, RSV1={1}, RSV2={2}, RSV3={3}, Opcode={4},
MASK={5}, Payload Len={6}, Extended Payload Len={7},
Masking Key ={8},
Payload Data={9}";
buffer = ToBytes();
count = (long)(Length / 4);
remainder = (int)(Length % 4);
if (count < 10000)
{
countDigit = 4;
countFmt = "{0,4}";
}
else if (count < 0x010000)
{
countDigit = 4;
countFmt = "{0,4:X}";
}
else if (count < 0x0100000000)
{
countDigit = 8;
countFmt = "{0,8:X}";
}
else
{
countDigit = 16;
countFmt = "{0,16:X}";
}
spFmt = String.Format("{{0,{0}}}", countDigit);
topLineFmt = String.Format(@"
{0} 01234567 89ABCDEF 01234567 89ABCDEF
{0}+--------+--------+--------+--------+", spFmt);
Func<string, Action<string, string, string, string>> func = s =>
{
long lineCount = 0;
string lineFmt = String.Format(" {0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|", s);
return (arg1, arg2, arg3, arg4) =>
{
Console.WriteLine(lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
};
};
var printLine = func(countFmt);
bottomLineFmt = String.Format(" {0}+--------+--------+--------+--------+", spFmt);
Console.WriteLine(headerFmt,
Fin, Rsv1, Rsv2, Rsv3, Opcode,
Masked, PayloadLen, extPayloadLen,
BitConverter.ToString(MaskingKey),
payloadData);
Console.WriteLine(topLineFmt, String.Empty);
for (i = 0; i <= count; i++)
{
j = i * 4;
if (i < count)
{
printLine(
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0'),
Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0'),
Convert.ToString(buffer[j + 3], 2).PadLeft(8, '0'));
}
else if (i == count && remainder > 0)
{
printLine(
Convert.ToString(buffer[j], 2).PadLeft(8, '0'),
remainder >= 2 ? Convert.ToString(buffer[j + 1], 2).PadLeft(8, '0') : String.Empty,
remainder == 3 ? Convert.ToString(buffer[j + 2], 2).PadLeft(8, '0') : String.Empty,
String.Empty);
}
}
Console.WriteLine(bottomLineFmt, String.Empty);
}
public byte[] ToBytes()
{
var bytes = new List<byte>();
int first16 = (int)Fin;
first16 = (first16 << 1) + (int)Rsv1;
first16 = (first16 << 1) + (int)Rsv2;
first16 = (first16 << 1) + (int)Rsv3;
first16 = (first16 << 4) + (int)Opcode;
first16 = (first16 << 1) + (int)Masked;
first16 = (first16 << 7) + (int)PayloadLen;
bytes.AddRange(((ushort)first16).ToBytes(ByteOrder.BIG));
if (PayloadLen >= 126)
{
bytes.AddRange(ExtPayloadLen);
}
if (Masked == Mask.MASK)
{
bytes.AddRange(MaskingKey);
}
if (PayloadLen > 0)
{
bytes.AddRange(PayloadData.ToBytes());
}
return bytes.ToArray();
}
public override string ToString()
{
return BitConverter.ToString(ToBytes());
}
#endregion
}
}

View File

@ -0,0 +1,87 @@
#region MIT License
/**
* MessageEventArgs.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using System.Text;
using WebSocketSharp.Frame;
namespace WebSocketSharp
{
public class MessageEventArgs : EventArgs
{
private Opcode _type;
private PayloadData _data;
public Opcode Type
{
get
{
return _type;
}
}
public string Data
{
get
{
if (((Opcode.TEXT | Opcode.PING | Opcode.PONG) & _type) == _type)
{
if (_data.Length > 0)
{
return Encoding.UTF8.GetString(_data.ToBytes());
}
else
{
return String.Empty;
}
}
return _type.ToString();
}
}
public byte[] RawData
{
get
{
return _data.ToBytes();
}
}
public MessageEventArgs(string data)
: this(Opcode.TEXT, new PayloadData(data))
{
}
public MessageEventArgs(Opcode type, PayloadData data)
{
_type = type;
_data = data;
}
}
}

View File

@ -4,7 +4,7 @@
*
* The MIT License
*
* Copyright (c) 2010 sta.blockhead
* Copyright (c) 2010-2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -27,15 +27,18 @@
#endregion
using System;
using WebSocketSharp.Frame;
namespace WebSocketSharp
namespace WebSocketSharp.Stream
{
public interface IWsStream : IDisposable
{
void Close();
int Read(byte[] buffer, int offset, int size);
int ReadByte();
void Write(byte[] buffer, int offset, int count);
void WriteByte(byte value);
void Close();
int Read(byte[] buffer, int offset, int size);
int ReadByte();
WsFrame ReadFrame();
void Write(byte[] buffer, int offset, int count);
void WriteByte(byte value);
void WriteFrame(WsFrame frame);
}
}

View File

@ -4,7 +4,7 @@
*
* The MIT License
*
* Copyright (c) 2010 sta.blockhead
* Copyright (c) 2010-2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -32,21 +32,24 @@ using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using WebSocketSharp.Frame;
namespace WebSocketSharp
namespace WebSocketSharp.Stream
{
public class WsStream<T> : IWsStream
where T : Stream
public class WsStream<TStream> : IWsStream
where TStream : System.IO.Stream
{
private T innerStream;
private TStream _innerStream;
private Object _forRead;
private Object _forWrite;
public WsStream(T innerStream)
public WsStream(TStream innerStream)
{
Type streamType = typeof(T);
Type streamType = typeof(TStream);
if (streamType != typeof(NetworkStream) &&
streamType != typeof(SslStream))
{
throw new NotSupportedException("Unsupported Stream type: " + streamType.ToString());
throw new NotSupportedException("Not supported Stream type: " + streamType.ToString());
}
if (innerStream == null)
@ -54,37 +57,56 @@ namespace WebSocketSharp
throw new ArgumentNullException("innerStream");
}
this.innerStream = innerStream;
_innerStream = innerStream;
_forRead = new object();
_forWrite = new object();
}
public void Close()
{
innerStream.Close();
_innerStream.Close();
}
public void Dispose()
{
innerStream.Dispose();
_innerStream.Dispose();
}
public int Read(byte[] buffer, int offset, int size)
{
return innerStream.Read(buffer, offset, size);
return _innerStream.Read(buffer, offset, size);
}
public int ReadByte()
{
return innerStream.ReadByte();
return _innerStream.ReadByte();
}
public WsFrame ReadFrame()
{
lock (_forRead)
{
return WsFrame.Parse(_innerStream);
}
}
public void Write(byte[] buffer, int offset, int count)
{
innerStream.Write(buffer, offset, count);
_innerStream.Write(buffer, offset, count);
}
public void WriteByte(byte value)
{
innerStream.WriteByte(value);
_innerStream.WriteByte(value);
}
public void WriteFrame(WsFrame frame)
{
lock (_forWrite)
{
var buffer = frame.ToBytes();
_innerStream.Write(buffer, 0, buffer.Length);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
#region MIT License
/**
* WsReceivedTooBigMessageException.cs
*
* The MIT License
*
* Copyright (c) 2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#endregion
using System;
using WebSocketSharp.Frame;
namespace WebSocketSharp
{
public class WsReceivedTooBigMessageException : Exception
{
private static readonly string _defaultMessage;
static WsReceivedTooBigMessageException()
{
_defaultMessage = String.Format(
"Client received a payload data bigger than the allowable value({0} bytes).", PayloadData.MaxLength);
}
public WsReceivedTooBigMessageException()
: this(_defaultMessage)
{
}
public WsReceivedTooBigMessageException(string message)
: base(message)
{
}
}
}

View File

@ -4,7 +4,7 @@
*
* The MIT License
*
* Copyright (c) 2010 sta.blockhead
* Copyright (c) 2010-2012 sta.blockhead
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -52,17 +52,30 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
<Package>notify-sharp</Package>
</Reference>
<Reference Include="System.ServiceModel" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Ext.cs" />
<Compile Include="WebSocket.cs" />
<Compile Include="WsState.cs" />
<Compile Include="IWsStream.cs" />
<Compile Include="WsStream.cs" />
<Compile Include="MessageEventArgs.cs" />
<Compile Include="CloseEventArgs.cs" />
<Compile Include="WsReceivedTooBigMessageException.cs" />
<Compile Include="ByteOrder.cs" />
<Compile Include="Stream\IWsStream.cs" />
<Compile Include="Stream\WsStream.cs" />
<Compile Include="Frame\WsFrame.cs" />
<Compile Include="Frame\CloseStatusCode.cs" />
<Compile Include="Frame\Fin.cs" />
<Compile Include="Frame\Mask.cs" />
<Compile Include="Frame\Opcode.cs" />
<Compile Include="Frame\PayloadData.cs" />
<Compile Include="Frame\Rsv.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Stream\" />
<Folder Include="Frame\" />
</ItemGroup>
</Project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,67 +0,0 @@
#if NOTIFY
using Notifications;
#endif
using System;
using System.Threading;
using WebSocketSharp;
namespace Example
{
public class Program
{
public static void Main(string[] args)
{
//using (WebSocket ws = new WebSocket("ws://localhost:8000/"))
using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat"))
{
ws.OnOpen += (o, e) =>
{
ws.Send("Hi, all!");
};
ws.OnMessage += (o, s) =>
{
#if NOTIFY
Notification nf = new Notification("[WebSocket] Message",
s,
"notification-message-im");
nf.AddHint("append", "allowed");
nf.Show();
#else
Console.WriteLine("[WebSocket] Message: {0}", s);
#endif
};
ws.OnError += (o, s) =>
{
Console.WriteLine("[WebSocket] Error : {0}", s);
};
/*ws.OnClose += (o, e) =>
{
//Do something.
};
*/
ws.Connect();
Thread.Sleep(500);
Console.WriteLine("\nType \"exit\" to exit.\n");
string data;
while (true)
{
Thread.Sleep(500);
Console.Write("> ");
data = Console.ReadLine();
if (data == "exit")
{
break;
}
ws.Send(data);
}
}
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,65 +0,0 @@
#if NOTIFY
using Notifications;
#endif
using System;
using System.Threading;
using WebSocketSharp;
namespace Example
{
public class Program
{
public static void Main(string[] args)
{
EventHandler onOpen = (o, e) =>
{
Console.WriteLine("[WebSocket] Opened.");
};
MessageEventHandler onMessage = (o, s) =>
{
#if NOTIFY
Notification nf = new Notification("[WebSocket] Message",
s,
"notification-message-im");
nf.AddHint("append", "allowed");
nf.Show();
#else
Console.WriteLine("[WebSocket] Message: {0}", s);
#endif
};
MessageEventHandler onError = (o, s) =>
{
Console.WriteLine("[WebSocket] Error : {0}", s);
};
EventHandler onClose = (o, e) =>
{
Console.WriteLine("[WebSocket] Closed.");
};
//using (WebSocket ws = new WebSocket("ws://localhost:8000/", onOpen, onMessage, onError, onClose))
using (WebSocket ws = new WebSocket("ws://localhost:8000/", "chat", onOpen, onMessage, onError, onClose))
{
Thread.Sleep(500);
Console.WriteLine("\nType \"exit\" to exit.\n");
string data;
while (true)
{
Thread.Sleep(500);
Console.Write("> ");
data = Console.ReadLine();
if (data == "exit")
{
break;
}
ws.Send(data);
}
}
}
}
}

View File

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{B0B609B7-A81C-46B0-A9B8-82E9716D355B}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>wsclient1</RootNamespace>
<AssemblyName>wsclient1</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_Ubuntu|AnyCPU' ">
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug_Ubuntu</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DebugSymbols>true</DebugSymbols>
<Externalconsole>true</Externalconsole>
<DefineConstants>DEBUG,NOTIFY</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_Ubuntu|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release_Ubuntu</OutputPath>
<DefineConstants>NOTIFY</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="notify-sharp, Version=0.4.0.0, Culture=neutral, PublicKeyToken=2df29c54e245917a">
<Package>notify-sharp</Package>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="wsclient1.cs" />
<Compile Include="AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\websocket-sharp\websocket-sharp.csproj">
<Project>{B357BAC7-529E-4D81-A0D2-71041B19C8DE}</Project>
<Name>websocket-sharp</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Binary file not shown.