Fix due to the added SessionManager.cs

This commit is contained in:
sta 2012-10-09 12:14:55 +09:00
parent 94385ea2bc
commit c560d4fba9
66 changed files with 345 additions and 245 deletions

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.

Binary file not shown.

Binary file not shown.

View File

@ -32,8 +32,8 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace WebSocketSharp.Frame
{
namespace WebSocketSharp.Frame {
public class WsFrame : IEnumerable<byte>
{
#region Field
@ -42,37 +42,6 @@ namespace WebSocketSharp.Frame
#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()
@ -120,6 +89,37 @@ namespace WebSocketSharp.Frame
#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 Private Methods
IEnumerator IEnumerable.GetEnumerator()

View File

@ -1,6 +1,6 @@
//
// EndPointManager.cs
// Copied from System.Net.EndPointManager
// Copied from System.Net.EndPointManager.cs
//
// Author:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)

View File

@ -39,12 +39,12 @@ namespace WebSocketSharp.Server {
#region Fields
private Thread _acceptRequestThread;
private bool _isWindows;
private HttpListener _listener;
private int _port;
private string _rootPath;
private Dictionary<string, IWebSocketServer> _wsServers;
private Thread _acceptRequestThread;
private bool _isWindows;
private HttpListener _listener;
private int _port;
private string _rootPath;
private Dictionary<string, IServiceHost> _services;
#endregion
@ -119,7 +119,7 @@ namespace WebSocketSharp.Server {
{
_isWindows = false;
_listener = new HttpListener();
_wsServers = new Dictionary<string, IWebSocketServer>();
_services = new Dictionary<string, IServiceHost>();
var os = Environment.OSVersion;
if (os.Platform != PlatformID.Unix && os.Platform != PlatformID.MacOSX)
@ -248,7 +248,7 @@ namespace WebSocketSharp.Server {
var res = context.Response;
var path = req.RawUrl;
if (!_wsServers.ContainsKey(path))
if (!_services.ContainsKey(path))
{
res.StatusCode = (int)HttpStatusCode.NotImplemented;
return false;
@ -256,8 +256,8 @@ namespace WebSocketSharp.Server {
var wsContext = context.AcceptWebSocket(path);
var socket = wsContext.WebSocket;
var wsServer = _wsServers[path];
wsServer.BindWebSocket(socket);
var service = _services[path];
service.BindWebSocket(socket);
return true;
}
@ -269,8 +269,8 @@ namespace WebSocketSharp.Server {
public void AddService<T>(string path)
where T : WebSocketService, new()
{
var server = new WebSocketServer<T>();
_wsServers.Add(path, server);
var service = new WebSocketServer<T>();
_services.Add(path, service);
}
public byte[] GetFile(string path)
@ -295,9 +295,9 @@ namespace WebSocketSharp.Server {
{
_listener.Close();
_acceptRequestThread.Join(5 * 1000);
foreach (var server in _wsServers.Values)
server.Stop();
_wsServers.Clear();
foreach (var service in _services.Values)
service.Stop();
_services.Clear();
}
#endregion

View File

@ -1,6 +1,6 @@
#region MIT License
/**
* IWebSocketServer.cs
* IServiceHost.cs
*
* The MIT License
*
@ -30,11 +30,10 @@ using System;
namespace WebSocketSharp.Server {
public interface IWebSocketServer {
public interface IServiceHost {
void BindWebSocket(WebSocket socket);
void Start();
void Stop();
void StopServices();
}
}

View File

@ -0,0 +1,184 @@
#region MIT License
/**
* SessionManager.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.Generic;
using WebSocketSharp.Frame;
namespace WebSocketSharp.Server {
public class SessionManager {
#region Private Fields
private bool _isStopped;
private Dictionary<string, WebSocketService> _sessions;
private object _syncRoot;
#endregion
#region Public Constructor
public SessionManager()
{
_isStopped = false;
_sessions = new Dictionary<string, WebSocketService>();
_syncRoot = new object();
}
#endregion
#region Properties
public int Count {
get {
lock (_syncRoot)
{
return _sessions.Count;
}
}
}
public object SyncRoot {
get {
return _syncRoot;
}
}
#endregion
#region Private Method
private Dictionary<string, WebSocketService> copySessions()
{
lock (_syncRoot)
{
return new Dictionary<string, WebSocketService>(_sessions);
}
}
private string getNewID()
{
return Guid.NewGuid().ToString("N");
}
#endregion
#region Public Methods
public string Add(WebSocketService service)
{
lock (_syncRoot)
{
if (_isStopped)
return null;
var id = getNewID();
_sessions.Add(id, service);
return id;
}
}
public void Broadcast(byte[] data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
}
}
public void Broadcast(string data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
}
}
public Dictionary<string, bool> Broadping(string data)
{
var result = new Dictionary<string, bool>();
foreach (var session in copySessions())
result.Add(session.Key, session.Value.Ping(data));
return result;
}
public IEnumerable<string> GetIDs()
{
lock (_syncRoot)
{
return _sessions.Keys;
}
}
public bool Remove(string id)
{
lock (_syncRoot)
{
if (_isStopped)
return false;
return _sessions.Remove(id);
}
}
public bool TryGetByID(string id, out WebSocketService service)
{
lock (_syncRoot)
{
return _sessions.TryGetValue(id, out service);
}
}
public void Stop()
{
Stop(CloseStatusCode.NORMAL, String.Empty);
}
public void Stop(CloseStatusCode code, string reason)
{
lock (_syncRoot)
{
if (_isStopped)
return;
_isStopped = true;
foreach (var service in _sessions.Values)
service.Stop(code, reason);
_sessions.Clear();
}
}
#endregion
}
}

View File

@ -29,10 +29,8 @@
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using WebSocketSharp.Frame;
using WebSocketSharp.Net;
using WebSocketSharp.Net.Sockets;
@ -42,7 +40,7 @@ namespace WebSocketSharp.Server {
{
#region Field
private Dictionary<string, IWebSocketServer> _servers;
private Dictionary<string, IServiceHost> _services;
#endregion
@ -56,7 +54,7 @@ namespace WebSocketSharp.Server {
public WebSocketServer(int port)
: base(System.Net.IPAddress.Any, port)
{
_servers = new Dictionary<string, IWebSocketServer>();
_services = new Dictionary<string, IServiceHost>();
}
#endregion
@ -68,14 +66,14 @@ namespace WebSocketSharp.Server {
var context = client.AcceptWebSocket();
var socket = context.WebSocket;
var path = context.RequestUri.ToString();
if (!_servers.ContainsKey(path))
if (!_services.ContainsKey(path))
{
socket.Close(HttpStatusCode.NotImplemented);
return;
}
var server = _servers[path];
server.BindWebSocket(socket);
var service = _services[path];
service.BindWebSocket(socket);
}
#endregion
@ -85,28 +83,28 @@ namespace WebSocketSharp.Server {
public void AddService<T>(string path)
where T : WebSocketService, new()
{
var server = new WebSocketServer<T>();
_servers.Add(path, server);
var service = new WebSocketServer<T>();
_services.Add(path, service);
}
public override void Stop()
{
base.Stop();
foreach (var server in _servers.Values)
server.Stop();
_servers.Clear();
foreach (var service in _services.Values)
service.Stop();
_services.Clear();
}
#endregion
}
public class WebSocketServer<T> : WebSocketServerBase, IWebSocketServer
public class WebSocketServer<T> : WebSocketServerBase, IServiceHost
where T : WebSocketService, new()
{
#region Fields
private Dictionary<string, WebSocketService> _services;
private Uri _uri;
private SessionManager _sessions;
private Uri _uri;
#endregion
@ -162,7 +160,7 @@ namespace WebSocketSharp.Server {
private void init()
{
_services = new Dictionary<string, WebSocketService>();
_sessions = new SessionManager();
}
#endregion
@ -182,29 +180,14 @@ namespace WebSocketSharp.Server {
public void BindWebSocket(WebSocket socket)
{
T service = new T();
service.Bind(socket, _services);
service.Bind(socket, _sessions);
service.Start();
}
public override void Stop()
{
base.Stop();
StopServices();
}
public void StopServices()
{
StopServices(CloseStatusCode.NORMAL, String.Empty);
}
public void StopServices(CloseStatusCode code, string reason)
{
lock (((ICollection)_services).SyncRoot)
{
foreach (WebSocketService service in _services.Values)
service.Stop(code, reason);
_services.Clear();
}
_sessions.Stop();
}
#endregion

View File

@ -27,7 +27,6 @@
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using WebSocketSharp.Frame;
@ -38,16 +37,8 @@ namespace WebSocketSharp.Server
{
#region Private Fields
private Dictionary<string, WebSocketService> _services;
private WebSocket _socket;
#endregion
#region Properties
public string ID { get; private set; }
public bool IsBound { get; private set; }
public bool IsStop { get; private set; }
private SessionManager _sessions;
private WebSocket _socket;
#endregion
@ -55,53 +46,37 @@ namespace WebSocketSharp.Server
public WebSocketService()
{
ID = String.Empty;
IsBound = false;
IsStop = false;
ID = String.Empty;
IsBound = false;
IsStopped = false;
}
#endregion
#region Properties
public string ID { get; private set; }
public bool IsBound { get; private set; }
public bool IsStopped { get; private set; }
#endregion
#region Private Method
private void addService(string id, WebSocketService service)
{
lock (((ICollection)_services).SyncRoot)
{
_services.Add(id, service);
}
}
private string getNewID()
{
return Guid.NewGuid().ToString("N");
}
private void defaultBind()
{
_socket.OnOpen += (sender, e) =>
{
ID = getNewID();
addService(ID, this);
ID = _sessions.Add(this);
};
_socket.OnClose += (sender, e) =>
{
if (!IsStop)
{
removeService(ID);
}
if (!IsStopped)
_sessions.Remove(ID);
};
}
private void removeService(string id)
{
lock (((ICollection)_services).SyncRoot)
{
_services.Remove(id);
}
}
#endregion
#region Protected Methods
@ -126,10 +101,10 @@ namespace WebSocketSharp.Server
#region Public Methods
public void Bind(WebSocket socket, Dictionary<string, WebSocketService> services)
public void Bind(WebSocket socket, SessionManager sessions)
{
_socket = socket;
_services = services;
_sessions = sessions;
defaultBind();
_socket.OnOpen += onOpen;
@ -159,12 +134,9 @@ namespace WebSocketSharp.Server
public Dictionary<string, bool> PingAround(string data)
{
if (!IsBound) return null;
lock (((ICollection)_services).SyncRoot)
{
return PingTo(_services.Keys, data);
}
return IsBound
? _sessions.Broadping(data)
: null;
}
public bool PingTo(string id)
@ -172,120 +144,83 @@ namespace WebSocketSharp.Server
return PingTo(id, String.Empty);
}
public Dictionary<string, bool> PingTo(IEnumerable<string> group)
{
return PingTo(group, String.Empty);
}
public bool PingTo(string id, string data)
{
if (!IsBound) return false;
if (!IsBound)
return false;
lock (((ICollection)_services).SyncRoot)
{
WebSocketService service;
return _services.TryGetValue(id, out service)
? service.Ping(data)
: false;
}
WebSocketService service;
return _sessions.TryGetByID(id, out service)
? service.Ping(data)
: false;
}
public Dictionary<string, bool> PingTo(IEnumerable<string> group, string data)
public void Publish(byte[] data)
{
if (!IsBound) return null;
var result = new Dictionary<string, bool>();
lock (((ICollection)_services).SyncRoot)
{
foreach (string id in group)
{
result.Add(id, PingTo(id, data));
}
}
return result;
if (IsBound)
_sessions.Broadcast(data);
}
public void Publish<TData>(TData data)
public void Publish(string data)
{
if (!IsBound) return;
WaitCallback broadcast = (state) =>
{
lock (((ICollection)_services).SyncRoot)
{
SendTo(_services.Keys, data);
}
};
ThreadPool.QueueUserWorkItem(broadcast);
if (IsBound)
_sessions.Broadcast(data);
}
public void Send(byte[] data)
{
if (IsBound) _socket.Send(data);
if (IsBound)
_socket.Send(data);
}
public void Send(string data)
{
if (IsBound) _socket.Send(data);
if (IsBound)
_socket.Send(data);
}
public void SendTo<TData>(string id, TData data)
public void SendAsync(byte[] data)
{
if (!IsBound) return;
if (typeof(TData) != typeof(string) &&
typeof(TData) != typeof(byte[]))
WaitCallback sendCb = (state) =>
{
var msg = "Type of data must be string or byte[].";
throw new ArgumentException(msg);
}
lock (((ICollection)_services).SyncRoot)
{
WebSocketService service;
if (_services.TryGetValue(id, out service))
{
if (typeof(TData) == typeof(string))
{
string data_ = (string)(object)data;
service.Send(data_);
}
else if (typeof(TData) == typeof(byte[]))
{
byte[] data_ = (byte[])(object)data;
service.Send(data_);
}
}
}
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
public void SendTo<TData>(IEnumerable<string> group, TData data)
public void SendAsync(string data)
{
if (!IsBound) return;
if (typeof(TData) != typeof(string) &&
typeof(TData) != typeof(byte[]))
WaitCallback sendCb = (state) =>
{
var msg = "Type of data must be string or byte[].";
throw new ArgumentException(msg);
}
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
lock (((ICollection)_services).SyncRoot)
{
foreach (string id in group)
{
SendTo(id, data);
}
}
public void SendTo(string id, byte[] data)
{
if (!IsBound)
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
service.Send(data);
}
public void SendTo(string id, string data)
{
if (!IsBound)
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
service.Send(data);
}
public void Start()
{
if (IsBound) _socket.Connect();
if (IsBound)
_socket.Connect();
}
public void Stop()
@ -295,9 +230,10 @@ namespace WebSocketSharp.Server
public void Stop(CloseStatusCode code, string reason)
{
if (!IsBound || IsStop) return;
if (!IsBound || IsStopped)
return;
IsStop = true;
IsStopped = true;
_socket.Close(code, reason);
}

View File

@ -32,11 +32,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@ -588,12 +586,9 @@ namespace WebSocketSharp {
{
try
{
MessageEventArgs eventArgs = receive();
var eventArgs = receive();
if (eventArgs != null)
{
OnMessage.Emit(this, eventArgs);
}
}
catch (WsReceivedTooBigMessageException ex)
{
@ -609,7 +604,6 @@ namespace WebSocketSharp {
{
Action messageInvoker = (Action)ar.AsyncState;
messageInvoker.EndInvoke(ar);
if (_readyState == WsState.OPEN)
{
messageInvoker.BeginInvoke(messageLoopCallback, messageInvoker);
@ -619,6 +613,22 @@ namespace WebSocketSharp {
_exitMessageLoop.Set();
}
private bool ping(string data, int millisecondsTimeout)
{
var buffer = Encoding.UTF8.GetBytes(data);
if (buffer.Length > 125)
{
var msg = "Ping frame must have a payload length of 125 bytes or less.";
error(msg);
return false;
}
if (!send(Fin.FINAL, Opcode.PING, buffer))
return false;
return _receivePong.WaitOne(millisecondsTimeout);
}
private void pong(PayloadData data)
{
var frame = createFrame(Fin.FINAL, Opcode.PONG, data);
@ -643,12 +653,11 @@ namespace WebSocketSharp {
return frame;
}
private WsFrame readFrameWithTimeout()
private WsFrame readFrameWithTimeout(int millisecondsTimeout)
{
if (!_wsStream.DataAvailable)
{
var timeout = 1 * 100;
Thread.Sleep(timeout);
Thread.Sleep(millisecondsTimeout);
if (!_wsStream.DataAvailable)
return null;
}
@ -663,7 +672,7 @@ namespace WebSocketSharp {
private MessageEventArgs receive()
{
var frame = _isClient ? readFrame() : readFrameWithTimeout();
var frame = _isClient ? readFrame() : readFrameWithTimeout(1 * 100);
if (frame == null)
return null;
@ -939,7 +948,6 @@ namespace WebSocketSharp {
private void startMessageThread()
{
_exitMessageLoop = new AutoResetEvent(false);
Action messageInvoker = () =>
{
if (_readyState == WsState.OPEN)
@ -1022,18 +1030,7 @@ namespace WebSocketSharp {
public bool Ping(string data)
{
var buffer = Encoding.UTF8.GetBytes(data);
if (buffer.Length > 125)
{
var msg = "Ping frame must have a payload length of 125 bytes or less.";
error(msg);
return false;
}
if (!send(Fin.FINAL, Opcode.PING, buffer))
return false;
return _receivePong.WaitOne(5 * 1000);
return ping(data, 5 * 1000);
}
public void Send(string data)

View File

@ -107,10 +107,11 @@
<Compile Include="Server\ResponseEventArgs.cs" />
<Compile Include="Net\HttpVersion.cs" />
<Compile Include="Net\HttpStatusCode.cs" />
<Compile Include="Server\IWebSocketServer.cs" />
<Compile Include="Net\Sockets\TcpListenerWebSocketContext.cs" />
<Compile Include="Server\WebSocketServerBase.cs" />
<Compile Include="Net\Security\SslStream.cs" />
<Compile Include="Server\IServiceHost.cs" />
<Compile Include="Server\SessionManager.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Binary file not shown.