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
@@ -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
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();
}
}
}
@@ -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
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();
}
}
}
@@ -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
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);
}
}
}
}
}
+165 -2
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
+10 -10
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
+4 -4
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>
+1 -1
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.
+38
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
}
}
+87
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;
}
}
}
+249 -89
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();
}
}
}
+59
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.
}
}
+38
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
}
}
+38
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
}
}
+43
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
}
}
+184
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
}
}
+38
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
}
}
+461
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
}
}
+87
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;
}
}
}
@@ -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);
}
}
@@ -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
@@ -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)
{
}
}
}
+1 -1
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+18 -5
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-67
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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-65
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);
}
}
}
}
}
-68
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.