Renamed SessionManager.cs to WebSocketServiceManager.cs

This commit is contained in:
sta
2013-02-02 23:44:06 +09:00
parent a171b05740
commit fcdf214fc0
53 changed files with 1821 additions and 791 deletions

View File

@@ -38,23 +38,23 @@ namespace WebSocketSharp.Server {
public interface IServiceHost {
/// <summary>
/// Gets or sets a value indicating whether the WebSocket service host cleans up the inactive service client.
/// Gets or sets a value indicating whether the WebSocket service host cleans up the inactive service clients periodically.
/// </summary>
/// <value>
/// <c>true</c> if the WebSocket service host cleans up the inactive service client; otherwise, <c>false</c>.
/// <c>true</c> if the WebSocket service host cleans up the inactive service clients periodically; otherwise, <c>false</c>.
/// </value>
bool Sweeped { get; set; }
/// <summary>
/// Binds the specified <see cref="WebSocket"/> instance to the WebSocket service.
/// Binds the specified <see cref="WebSocket"/> to the WebSocket service instance.
/// </summary>
/// <param name="socket">
/// An <see cref="WebSocketSharp.WebSocket"/> to bind.
/// A <see cref="WebSocketSharp.WebSocket"/> to bind.
/// </param>
void BindWebSocket(WebSocket socket);
/// <summary>
/// Broadcasts the specified <see cref="string"/>.
/// Broadcasts the specified <see cref="string"/> to all service clients.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.

View File

@@ -1,312 +0,0 @@
#region MIT License
/*
* SessionManager.cs
*
* The MIT License
*
* Copyright (c) 2012-2013 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 System.Linq;
using System.Timers;
namespace WebSocketSharp.Server {
public class SessionManager {
#region Private Fields
private object _forSweep;
private volatile bool _isStopped;
private volatile bool _isSweeping;
private Dictionary<string, WebSocketService> _sessions;
private Timer _sweepTimer;
private object _syncRoot;
#endregion
#region Public Constructor
public SessionManager()
{
_forSweep = new object();
_isStopped = false;
_isSweeping = false;
_sessions = new Dictionary<string, WebSocketService>();
_sweepTimer = new Timer(60 * 1000);
_sweepTimer.Elapsed += (sender, e) =>
{
Sweep();
};
_syncRoot = new object();
startSweepTimer();
}
#endregion
#region Properties
public IEnumerable<string> ActiveID {
get {
return from result in Broadping(String.Empty)
where result.Value
select result.Key;
}
}
public int Count {
get {
lock (_syncRoot)
{
return _sessions.Count;
}
}
}
public IEnumerable<string> InactiveID {
get {
return from result in Broadping(String.Empty)
where !result.Value
select result.Key;
}
}
public IEnumerable<string> ID {
get {
lock (_syncRoot)
{
return _sessions.Keys;
}
}
}
public bool Sweeped {
get {
return _sweepTimer.Enabled;
}
set {
if (value && !_isStopped)
startSweepTimer();
if (!value)
stopSweepTimer();
}
}
public object SyncRoot {
get {
return _syncRoot;
}
}
#endregion
#region Private Methods
private void broadcast(byte[] data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.Send(data);
}
}
private void broadcast(string data)
{
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.Send(data);
}
}
private void broadcastAsync(byte[] data)
{
var sessions = copySessions();
var services = sessions.Values.GetEnumerator();
Action completed = null;
completed = () =>
{
if (services.MoveNext())
services.Current.SendAsync(data, completed);
};
if (services.MoveNext())
services.Current.SendAsync(data, completed);
}
private void broadcastAsync(string data)
{
var sessions = copySessions();
var services = sessions.Values.GetEnumerator();
Action completed = null;
completed = () =>
{
if (services.MoveNext())
services.Current.SendAsync(data, completed);
};
if (services.MoveNext())
services.Current.SendAsync(data, completed);
}
private Dictionary<string, WebSocketService> copySessions()
{
lock (_syncRoot)
{
return new Dictionary<string, WebSocketService>(_sessions);
}
}
private string createID()
{
return Guid.NewGuid().ToString("N");
}
private void startSweepTimer()
{
if (!Sweeped)
_sweepTimer.Start();
}
private void stopSweepTimer()
{
if (Sweeped)
_sweepTimer.Stop();
}
#endregion
#region Public Methods
public string Add(WebSocketService service)
{
lock (_syncRoot)
{
if (_isStopped)
return null;
var id = createID();
_sessions.Add(id, service);
return id;
}
}
public void Broadcast(byte[] data)
{
if (_isStopped)
broadcast(data);
else
broadcastAsync(data);
}
public void Broadcast(string data)
{
if (_isStopped)
broadcast(data);
else
broadcastAsync(data);
}
public Dictionary<string, bool> Broadping(string message)
{
var result = new Dictionary<string, bool>();
foreach (var session in copySessions())
result.Add(session.Key, session.Value.Ping(message));
return result;
}
public bool Remove(string id)
{
lock (_syncRoot)
{
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)
{
stopSweepTimer();
lock (_syncRoot)
{
if (_isStopped)
return;
_isStopped = true;
foreach (var service in copySessions().Values)
service.Stop(code, reason);
}
}
public void Sweep()
{
if (_isStopped || _isSweeping || Count == 0)
return;
lock (_forSweep)
{
_isSweeping = true;
foreach (var id in InactiveID)
{
lock (_syncRoot)
{
if (_isStopped)
{
_isSweeping = false;
return;
}
WebSocketService service;
if (TryGetByID(id, out service))
service.Stop(CloseStatusCode.ABNORMAL, String.Empty);
}
}
_isSweeping = false;
}
}
#endregion
}
}

View File

@@ -111,7 +111,7 @@ namespace WebSocketSharp.Server {
/// on the specified <paramref name="address"/> and <paramref name="port"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains an IP address.
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
/// </param>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
@@ -126,7 +126,7 @@ namespace WebSocketSharp.Server {
/// on the specified <paramref name="address"/>, <paramref name="port"/> and <paramref name="secure"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains an IP address.
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
/// </param>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
@@ -145,10 +145,10 @@ namespace WebSocketSharp.Server {
#region Properties
/// <summary>
/// Gets the paths associated with the each WebSocket services.
/// Gets the collection of paths associated with the every WebSocket services that the server provides.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the paths.
/// An IEnumerable&lt;string&gt; that contains the collection of paths.
/// </value>
public IEnumerable<string> ServicePaths {
get {
@@ -161,10 +161,10 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Gets or sets a value indicating whether the server cleans up the inactive client.
/// Gets or sets a value indicating whether the server cleans up the inactive clients periodically.
/// </summary>
/// <value>
/// <c>true</c> if the server cleans up the inactive client; otherwise, <c>false</c>.
/// <c>true</c> if the server cleans up the inactive clients every 60 seconds; otherwise, <c>false</c>.
/// </value>
public bool Sweeped {
get {
@@ -193,7 +193,7 @@ namespace WebSocketSharp.Server {
/// Accepts a WebSocket connection.
/// </summary>
/// <param name="context">
/// A <see cref="TcpListenerWebSocketContext"/> that contains a WebSocket connection.
/// A <see cref="TcpListenerWebSocketContext"/> that contains the WebSocket connection request objects.
/// </param>
protected override void AcceptWebSocket(TcpListenerWebSocketContext context)
{
@@ -221,10 +221,10 @@ namespace WebSocketSharp.Server {
/// Adds a WebSocket service.
/// </summary>
/// <param name="absPath">
/// A <see cref="string"/> that contains an absolute path associated with a WebSocket service.
/// A <see cref="string"/> that contains an absolute path associated with the WebSocket service.
/// </param>
/// <typeparam name="T">
/// The type of a WebSocket service. The T must inherit the <see cref="WebSocketService"/> class.
/// The type of the WebSocket service. The T must inherit the <see cref="WebSocketService"/> class.
/// </typeparam>
public void AddService<T>(string absPath)
where T : WebSocketService, new()

View File

@@ -96,7 +96,7 @@ namespace WebSocketSharp.Server {
/// on the specified <paramref name="address"/>, <paramref name="port"/>, <paramref name="absPath"/> and <paramref name="secure"/>.
/// </summary>
/// <param name="address">
/// A <see cref="IPAddress"/> that contains an IP address.
/// A <see cref="IPAddress"/> that contains a local IP address.
/// </param>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
@@ -177,10 +177,10 @@ namespace WebSocketSharp.Server {
#region Public Properties
/// <summary>
/// Gets the IP address on which to listen for incoming connection attempts.
/// Gets the local IP address on which to listen for incoming connection attempts.
/// </summary>
/// <value>
/// A <see cref="IPAddress"/> that contains an IP address.
/// A <see cref="IPAddress"/> that contains a local IP address.
/// </value>
public IPAddress Address {
get {
@@ -189,10 +189,10 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Gets a value indicating whether this server provides secure connection.
/// Gets a value indicating whether the server provides secure connection.
/// </summary>
/// <value>
/// <c>true</c> if this server provides secure connection; otherwise, <c>false</c>.
/// <c>true</c> if the server provides secure connection; otherwise, <c>false</c>.
/// </value>
public bool IsSecure {
get {
@@ -201,10 +201,10 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Gets a value indicating whether this server is self host.
/// Gets a value indicating whether the server is self host.
/// </summary>
/// <value>
/// <c>true</c> if this server is self host; otherwise, <c>false</c>.
/// <c>true</c> if the server is self host; otherwise, <c>false</c>.
/// </value>
public bool IsSelfHost {
get {
@@ -339,7 +339,7 @@ namespace WebSocketSharp.Server {
/// Accepts a WebSocket connection.
/// </summary>
/// <param name="context">
/// A <see cref="TcpListenerWebSocketContext"/> that contains a WebSocket connection.
/// A <see cref="TcpListenerWebSocketContext"/> that contains the WebSocket connection request objects.
/// </param>
protected abstract void AcceptWebSocket(TcpListenerWebSocketContext context);

View File

@@ -43,8 +43,8 @@ namespace WebSocketSharp.Server {
#region Private Fields
private SessionManager _sessions;
private WebSocket _socket;
private WebSocketServiceManager _sessions;
private WebSocket _socket;
#endregion
@@ -79,9 +79,9 @@ namespace WebSocketSharp.Server {
/// Gets the sessions to the WebSocket service.
/// </summary>
/// <value>
/// A <see cref="SessionManager"/> that contains the sessions to the WebSocket service.
/// A <see cref="WebSocketServiceManager"/> that contains the sessions to the WebSocket service.
/// </value>
protected SessionManager Sessions {
protected WebSocketServiceManager Sessions {
get {
return IsBound ? _sessions : null;
}
@@ -92,18 +92,18 @@ namespace WebSocketSharp.Server {
#region Public Properties
/// <summary>
/// Gets the ID of a <see cref="WebSocketService"/> instance.
/// Gets the ID of the <see cref="WebSocketService"/> instance.
/// </summary>
/// <value>
/// A <see cref="string"/> that contains a ID.
/// A <see cref="string"/> that contains an ID.
/// </value>
public string ID { get; private set; }
/// <summary>
/// Gets a value indicating whether a <see cref="WebSocketService"/> instance is bound to a <see cref="WebSocket"/>.
/// Gets a value indicating whether the <see cref="WebSocketService"/> instance is bound to a <see cref="WebSocket"/>.
/// </summary>
/// <value>
/// <c>true</c> if the WebSocketService is bound to a WebSocket; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance is bound to a <see cref="WebSocket"/>; otherwise, <c>false</c>.
/// </value>
public bool IsBound { get; private set; }
@@ -137,6 +137,22 @@ namespace WebSocketSharp.Server {
#region Internal Methods
internal void Bind(WebSocket socket, WebSocketServiceManager sessions)
{
if (IsBound)
return;
_socket = socket;
_sessions = sessions;
_socket.OnOpen += onOpen;
_socket.OnMessage += onMessage;
_socket.OnError += onError;
_socket.OnClose += onClose;
IsBound = true;
}
internal void SendAsync(byte[] data, Action completed)
{
_socket.SendAsync(data, completed);
@@ -152,7 +168,7 @@ namespace WebSocketSharp.Server {
#region Protected Methods
/// <summary>
/// Occurs when a inner <see cref="WebSocket"/> receives a Close frame or the Stop method is called.
/// Occurs when the inner <see cref="WebSocket"/> receives a Close frame or the Stop method is called.
/// </summary>
/// <param name="e">
/// A <see cref="CloseEventArgs"/> that contains the event data associated with a <see cref="WebSocket.OnClose"/> event.
@@ -162,7 +178,7 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Occurs when a inner <see cref="WebSocket"/> gets an error.
/// Occurs when the inner <see cref="WebSocket"/> gets an error.
/// </summary>
/// <param name="e">
/// An <see cref="ErrorEventArgs"/> that contains the event data associated with a <see cref="WebSocket.OnError"/> event.
@@ -172,7 +188,7 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Occurs when a inner <see cref="WebSocket"/> receives a data frame.
/// Occurs when the inner <see cref="WebSocket"/> receives a data frame.
/// </summary>
/// <param name="e">
/// A <see cref="MessageEventArgs"/> that contains the event data associated with a <see cref="WebSocket.OnMessage"/> event.
@@ -193,33 +209,8 @@ namespace WebSocketSharp.Server {
#region Public Methods
/// <summary>
/// Binds the specified <see cref="WebSocket"/> and <see cref="SessionManager"/>
/// to a <see cref="WebSocketService"/> instance.
/// </summary>
/// <param name="socket">
/// A <see cref="WebSocket"/> to bind to the WebSocketService.
/// </param>
/// <param name="sessions">
/// A <see cref="SessionManager"/> to bind to the WebSocketService.
/// </param>
public void Bind(WebSocket socket, SessionManager sessions)
{
if (IsBound)
return;
_socket = socket;
_sessions = sessions;
_socket.OnOpen += onOpen;
_socket.OnMessage += onMessage;
_socket.OnError += onError;
_socket.OnClose += onClose;
IsBound = true;
}
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to all clients of the WebSocket service.
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
@@ -231,7 +222,8 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to all clients of the WebSocket service.
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
@@ -243,11 +235,12 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings to all clients of the WebSocket service.
/// Pings to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of the ID and value
/// indicating whether the WebSocket service received a Pong in a time.
/// A Dictionary&lt;string, bool&gt; that contains the collection of IDs and values
/// indicating whether each <see cref="WebSocketService"/> instances received a Pong in a time.
/// </returns>
public Dictionary<string, bool> Broadping()
{
@@ -255,11 +248,12 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings with the specified <see cref="string"/> to all clients of the WebSocket service.
/// Pings with the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/> instances
/// in the <see cref="WebSocketService.Sessions"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of the ID and value
/// indicating whether the WebSocket service received a Pong in a time.
/// A Dictionary&lt;string, bool&gt; that contains the collection of IDs and values
/// indicating whether each <see cref="WebSocketService"/> instances received a Pong in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message.
@@ -272,10 +266,10 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings to the client of a <see cref="WebSocketService"/> instance.
/// Pings to the client of the <see cref="WebSocketService"/> instance.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocketService receives a Pong in a time; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong in a time; otherwise, <c>false</c>.
/// </returns>
public bool Ping()
{
@@ -283,10 +277,10 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings with the specified <see cref="string"/> to the client of a <see cref="WebSocketService"/> instance.
/// Pings with the specified <see cref="string"/> to the client of the <see cref="WebSocketService"/> instance.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocketService receives a Pong in a time; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message.
@@ -299,13 +293,14 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings to the client of a <see cref="WebSocketService"/> instance associated with the specified ID.
/// Pings to the client of the <see cref="WebSocketService"/> instance
/// associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocket service receives a Pong in a time; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// </param>
public bool PingTo(string id)
{
@@ -313,14 +308,14 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Pings with the specified <see cref="string"/> to the client of a <see cref="WebSocketService"/> instance
/// associated with the specified ID.
/// Pings with the specified <see cref="string"/> to the client of the <see cref="WebSocketService"/> instance
/// associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the WebSocketService receives a Pong in a time; otherwise, <c>false</c>.
/// <c>true</c> if the <see cref="WebSocketService"/> instance receives a Pong in a time; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains a ID that represents the destination for the Ping.
/// A <see cref="string"/> that contains an ID that represents the destination for the Ping.
/// </param>
/// <param name="message">
/// A <see cref="string"/> that contains a message.
@@ -331,13 +326,13 @@ namespace WebSocketSharp.Server {
return false;
WebSocketService service;
return _sessions.TryGetByID(id, out service)
return _sessions.TryGetWebSocketService(id, out service)
? service.Ping(message)
: false;
}
/// <summary>
/// Sends a binary data to the client of a <see cref="WebSocketService"/> instance.
/// Sends a binary data to the client of the <see cref="WebSocketService"/> instance.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> that contains a binary data to send.
@@ -349,7 +344,7 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Sends a text data to the client of a <see cref="WebSocketService"/> instance.
/// Sends a text data to the client of the <see cref="WebSocketService"/> instance.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> that contains a text data to send.
@@ -361,10 +356,11 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Sends a binary data to the client of a <see cref="WebSocketService"/> instance associated with the specified ID.
/// Sends a binary data to the client of the <see cref="WebSocketService"/> instance
/// associated with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a ID that represents the destination for the data.
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// </param>
/// <param name="data">
/// An array of <see cref="byte"/> that contains a binary data to send.
@@ -375,15 +371,16 @@ namespace WebSocketSharp.Server {
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
if (_sessions.TryGetWebSocketService(id, out service))
service.Send(data);
}
/// <summary>
/// Sends a text data to the client of a <see cref="WebSocketService"/> instance associated with the specified ID.
/// Sends a text data to the client of the <see cref="WebSocketService"/> instance
/// associated with the specified <paramref name="id"/>.
/// </summary>
/// <param name="id">
/// A <see cref="string"/> that contains a ID that represents the destination for the data.
/// A <see cref="string"/> that contains an ID that represents the destination for the data.
/// </param>
/// <param name="data">
/// A <see cref="string"/> that contains a text data to send.
@@ -394,12 +391,12 @@ namespace WebSocketSharp.Server {
return;
WebSocketService service;
if (_sessions.TryGetByID(id, out service))
if (_sessions.TryGetWebSocketService(id, out service))
service.Send(data);
}
/// <summary>
/// Starts a <see cref="WebSocketService"/> instance.
/// Starts the <see cref="WebSocketService"/> instance.
/// </summary>
public void Start()
{
@@ -408,7 +405,7 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Stops a <see cref="WebSocketService"/> instance.
/// Stops the <see cref="WebSocketService"/> instance.
/// </summary>
public void Stop()
{
@@ -419,21 +416,7 @@ namespace WebSocketSharp.Server {
}
/// <summary>
/// Stops a <see cref="WebSocketService"/> instance with the specified <see cref="CloseStatusCode"/> and <see cref="string"/>.
/// </summary>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> values that contains a status code indicating the reason for stop.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains a reason for stop.
/// </param>
public void Stop(CloseStatusCode code, string reason)
{
Stop((ushort)code, reason);
}
/// <summary>
/// Stops a <see cref="WebSocketService"/> instance with the specified <see cref="ushort"/> and <see cref="string"/>.
/// Stops the <see cref="WebSocketService"/> instance with the specified <see cref="ushort"/> and <see cref="string"/>.
/// </summary>
/// <param name="code">
/// A <see cref="ushort"/> that contains a status code indicating the reason for stop.
@@ -449,6 +432,20 @@ namespace WebSocketSharp.Server {
_socket.Close(code, reason);
}
/// <summary>
/// Stops the <see cref="WebSocketService"/> instance with the specified <see cref="CloseStatusCode"/> and <see cref="string"/>.
/// </summary>
/// <param name="code">
/// One of the <see cref="CloseStatusCode"/> values that contains a status code indicating the reason for stop.
/// </param>
/// <param name="reason">
/// A <see cref="string"/> that contains a reason for stop.
/// </param>
public void Stop(CloseStatusCode code, string reason)
{
Stop((ushort)code, reason);
}
#endregion
}
}

View File

@@ -50,7 +50,7 @@ namespace WebSocketSharp.Server {
{
#region Field
private SessionManager _sessions;
private WebSocketServiceManager _sessions;
#endregion
@@ -143,7 +143,7 @@ namespace WebSocketSharp.Server {
/// on the specified <paramref name="address"/>, <paramref name="port"/> and <paramref name="absPath"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains an IP address.
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
/// </param>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
@@ -161,7 +161,7 @@ namespace WebSocketSharp.Server {
/// on the specified <paramref name="address"/>, <paramref name="port"/>, <paramref name="absPath"/> and <paramref name="secure"/>.
/// </summary>
/// <param name="address">
/// A <see cref="System.Net.IPAddress"/> that contains an IP address.
/// A <see cref="System.Net.IPAddress"/> that contains a local IP address.
/// </param>
/// <param name="port">
/// An <see cref="int"/> that contains a port number.
@@ -183,10 +183,10 @@ namespace WebSocketSharp.Server {
#region Properties
/// <summary>
/// Gets or sets a value indicating whether the server cleans up the inactive client.
/// Gets or sets a value indicating whether the server cleans up the inactive clients periodically.
/// </summary>
/// <value>
/// <c>true</c> if the server cleans up the inactive client; otherwise, <c>false</c>.
/// <c>true</c> if the server cleans up the inactive clients every 60 seconds; otherwise, <c>false</c>.
/// </value>
public bool Sweeped {
get {
@@ -220,7 +220,7 @@ namespace WebSocketSharp.Server {
private void init()
{
_sessions = new SessionManager();
_sessions = new WebSocketServiceManager();
}
#endregion
@@ -228,7 +228,7 @@ namespace WebSocketSharp.Server {
#region Explicit Interface Implementation
/// <summary>
/// Binds the specified <see cref="WebSocket"/> instance to the WebSocket service.
/// Binds the specified <see cref="WebSocket"/> to the WebSocket service instance.
/// </summary>
/// <param name="socket">
/// A <see cref="WebSocket"/> to bind.
@@ -248,7 +248,7 @@ namespace WebSocketSharp.Server {
/// Accepts a WebSocket connection.
/// </summary>
/// <param name="context">
/// A <see cref="TcpListenerWebSocketContext"/> that contains a WebSocket connection.
/// A <see cref="TcpListenerWebSocketContext"/> that contains the WebSocket connection request objects.
/// </param>
protected override void AcceptWebSocket(TcpListenerWebSocketContext context)
{
@@ -285,8 +285,8 @@ namespace WebSocketSharp.Server {
/// Pings with the specified <see cref="string"/> to all clients.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of the session ID and value
/// indicating whether the server received a Pong in a time.
/// A Dictionary&lt;string, bool&gt; that contains the collection of session IDs and values
/// indicating whether the server received the Pongs from each clients in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message.

View File

@@ -0,0 +1,408 @@
#region MIT License
/*
* WebSocketServiceManager.cs
*
* The MIT License
*
* Copyright (c) 2012-2013 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 System.Linq;
using System.Timers;
namespace WebSocketSharp.Server {
/// <summary>
/// Manages the collection of <see cref="WebSocketService"/> objects.
/// </summary>
public class WebSocketServiceManager {
#region Fields
private object _forSweep;
private volatile bool _isStopped;
private volatile bool _isSweeping;
private Dictionary<string, WebSocketService> _services;
private Timer _sweepTimer;
private object _syncRoot;
#endregion
#region Constructor
internal WebSocketServiceManager()
{
_forSweep = new object();
_isStopped = false;
_isSweeping = false;
_services = new Dictionary<string, WebSocketService>();
_syncRoot = new object();
setSweepTimer();
startSweepTimer();
}
#endregion
#region Properties
/// <summary>
/// Gets the collection of IDs of active <see cref="WebSocketService"/> objects
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the collection of IDs of active <see cref="WebSocketService"/> objects.
/// </value>
public IEnumerable<string> ActiveIDs {
get {
return from result in Broadping(String.Empty)
where result.Value
select result.Key;
}
}
/// <summary>
/// Gets the number of <see cref="WebSocketService"/> objects
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <value>
/// An <see cref="int"/> that contains the number of <see cref="WebSocketService"/> objects
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </value>
public int Count {
get {
lock (_syncRoot)
{
return _services.Count;
}
}
}
/// <summary>
/// Gets the collection of IDs of inactive <see cref="WebSocketService"/> objects
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the collection of IDs of inactive <see cref="WebSocketService"/> objects.
/// </value>
public IEnumerable<string> InactiveIDs {
get {
return from result in Broadping(String.Empty)
where !result.Value
select result.Key;
}
}
/// <summary>
/// Gets the collection of IDs of <see cref="WebSocketService"/> objects
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <value>
/// An IEnumerable&lt;string&gt; that contains the collection of IDs of <see cref="WebSocketService"/> objects.
/// </value>
public IEnumerable<string> IDs {
get {
lock (_syncRoot)
{
return _services.Keys;
}
}
}
/// <summary>
/// Gets a value indicating whether the <see cref="WebSocketServiceManager"/> cleans up
/// the inactive <see cref="WebSocketService"/> objects periodically.
/// </summary>
/// <value>
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> cleans up the inactive <see cref="WebSocketService"/> objects
/// every 60 seconds; otherwise, <c>false</c>.
/// </value>
public bool Sweeped {
get {
return _sweepTimer.Enabled;
}
internal set {
if (value && !_isStopped)
startSweepTimer();
if (!value)
stopSweepTimer();
}
}
#endregion
#region Private Methods
private void broadcast(byte[] data)
{
lock (_syncRoot)
{
foreach (var service in _services.Values)
service.Send(data);
}
}
private void broadcast(string data)
{
lock (_syncRoot)
{
foreach (var service in _services.Values)
service.Send(data);
}
}
private void broadcastAsync(byte[] data)
{
var copied = copy();
var services = copied.Values.GetEnumerator();
Action completed = null;
completed = () =>
{
if (services.MoveNext())
services.Current.SendAsync(data, completed);
};
if (services.MoveNext())
services.Current.SendAsync(data, completed);
}
private void broadcastAsync(string data)
{
var copied = copy();
var services = copied.Values.GetEnumerator();
Action completed = null;
completed = () =>
{
if (services.MoveNext())
services.Current.SendAsync(data, completed);
};
if (services.MoveNext())
services.Current.SendAsync(data, completed);
}
private Dictionary<string, WebSocketService> copy()
{
lock (_syncRoot)
{
return new Dictionary<string, WebSocketService>(_services);
}
}
private string createID()
{
return Guid.NewGuid().ToString("N");
}
private void setSweepTimer()
{
_sweepTimer = new Timer(60 * 1000);
_sweepTimer.Elapsed += (sender, e) =>
{
Sweep();
};
}
private void startSweepTimer()
{
if (!Sweeped)
_sweepTimer.Start();
}
private void stop(ushort code, string reason, bool ignoreArgs)
{
stopSweepTimer();
lock (_syncRoot)
{
if (_isStopped)
return;
_isStopped = true;
foreach (var service in copy().Values)
if (ignoreArgs)
service.Stop();
else
service.Stop(code, reason);
}
}
private void stopSweepTimer()
{
if (Sweeped)
_sweepTimer.Stop();
}
#endregion
#region Internal Methods
internal string Add(WebSocketService service)
{
lock (_syncRoot)
{
if (_isStopped)
return null;
var id = createID();
_services.Add(id, service);
return id;
}
}
internal bool Remove(string id)
{
lock (_syncRoot)
{
return _services.Remove(id);
}
}
internal void Stop()
{
stop(0, null, true);
}
internal void Stop(ushort code, string reason)
{
stop(code, reason, false);
}
internal void Stop(CloseStatusCode code, string reason)
{
Stop((ushort)code, reason);
}
#endregion
#region Public Methods
/// <summary>
/// Broadcasts the specified array of <see cref="byte"/> to the clients of every <see cref="WebSocketService"/>
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <param name="data">
/// An array of <see cref="byte"/> to broadcast.
/// </param>
public void Broadcast(byte[] data)
{
if (_isStopped)
broadcast(data);
else
broadcastAsync(data);
}
/// <summary>
/// Broadcasts the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <param name="data">
/// A <see cref="string"/> to broadcast.
/// </param>
public void Broadcast(string data)
{
if (_isStopped)
broadcast(data);
else
broadcastAsync(data);
}
/// <summary>
/// Pings with the specified <see cref="string"/> to the clients of every <see cref="WebSocketService"/>
/// managed by the <see cref="WebSocketServiceManager"/>.
/// </summary>
/// <returns>
/// A Dictionary&lt;string, bool&gt; that contains the collection of IDs and values
/// indicating whether each <see cref="WebSocketService"/> received a Pong in a time.
/// </returns>
/// <param name="message">
/// A <see cref="string"/> that contains a message.
/// </param>
public Dictionary<string, bool> Broadping(string message)
{
var result = new Dictionary<string, bool>();
foreach (var session in copy())
result.Add(session.Key, session.Value.Ping(message));
return result;
}
/// <summary>
/// Cleans up the inactive <see cref="WebSocketService"/> objects.
/// </summary>
public void Sweep()
{
if (_isStopped || _isSweeping || Count == 0)
return;
lock (_forSweep)
{
_isSweeping = true;
foreach (var id in InactiveIDs)
{
lock (_syncRoot)
{
if (_isStopped)
{
_isSweeping = false;
return;
}
WebSocketService service;
if (TryGetWebSocketService(id, out service))
service.Stop(CloseStatusCode.ABNORMAL, String.Empty);
}
}
_isSweeping = false;
}
}
/// <summary>
/// Tries to get the <see cref="WebSocketService"/> associated with the specified <paramref name="id"/>.
/// </summary>
/// <returns>
/// <c>true</c> if the <see cref="WebSocketServiceManager"/> manages the <see cref="WebSocketService"/> with the specified <paramref name="id"/>; otherwise, <c>false</c>.
/// </returns>
/// <param name="id">
/// A <see cref="string"/> that contains the ID to find.
/// </param>
/// <param name="service">
/// When this method returns, contains the <see cref="WebSocketService"/> with the specified <paramref name="id"/>, if the <paramref name="id"/> is found; otherwise, <see langword="null"/>.
/// </param>
public bool TryGetWebSocketService(string id, out WebSocketService service)
{
lock (_syncRoot)
{
return _services.TryGetValue(id, out service);
}
}
#endregion
}
}