Fix for issue #9 - 2

This commit is contained in:
sta
2012-10-26 14:58:50 +09:00
parent 2ae1d35d03
commit 746c883b82
71 changed files with 230 additions and 84 deletions

View File

@@ -63,12 +63,22 @@ namespace WebSocketSharp.Server {
#endregion
#region Property
#region Properties
public int Port {
get { return _port; }
}
public bool Sweeped {
get {
return _services.Sweeped;
}
set {
_services.Sweeped = value;
}
}
#endregion
#region Events

View File

@@ -32,6 +32,7 @@ namespace WebSocketSharp.Server {
public interface IServiceHost {
bool Sweeped { get; set; }
void BindWebSocket(WebSocket socket);
void Broadcast(string data);
void Start();

View File

@@ -36,6 +36,7 @@ namespace WebSocketSharp.Server {
#region Field
private Dictionary<string, IServiceHost> _services;
private bool _sweeped;
#endregion
@@ -44,11 +45,12 @@ namespace WebSocketSharp.Server {
public ServiceManager()
{
_services = new Dictionary<string, IServiceHost>();
_sweeped = true;
}
#endregion
#region Property
#region Properties
public int Count {
get {
@@ -56,6 +58,21 @@ namespace WebSocketSharp.Server {
}
}
public bool Sweeped {
get {
return _sweeped;
}
set {
if (value ^ _sweeped)
{
_sweeped = value;
foreach (var svcHost in _services.Values)
svcHost.Sweeped = value;
}
}
}
#endregion
#region Public Methods

View File

@@ -28,6 +28,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using WebSocketSharp.Frame;
namespace WebSocketSharp.Server {
@@ -36,8 +38,11 @@ namespace WebSocketSharp.Server {
#region Private Fields
private bool _isStopped;
private object _forSweep;
private volatile bool _isStopped;
private volatile bool _isSweeping;
private Dictionary<string, WebSocketService> _sessions;
private Timer _sweepTimer;
private object _syncRoot;
#endregion
@@ -46,15 +51,32 @@ namespace WebSocketSharp.Server {
public SessionManager()
{
_isStopped = false;
_sessions = new Dictionary<string, WebSocketService>();
_syncRoot = new object();
_forSweep = new object();
_isStopped = false;
_isSweeping = false;
_sessions = new Dictionary<string, WebSocketService>();
_sweepTimer = new Timer(30 * 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)
@@ -64,6 +86,37 @@ namespace WebSocketSharp.Server {
}
}
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;
@@ -82,11 +135,23 @@ namespace WebSocketSharp.Server {
}
}
private string getNewID()
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
@@ -98,7 +163,7 @@ namespace WebSocketSharp.Server {
if (_isStopped)
return null;
var id = getNewID();
var id = createID();
_sessions.Add(id, service);
return id;
@@ -110,7 +175,10 @@ namespace WebSocketSharp.Server {
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
if (_isStopped || _isSweeping)
service.Send(data);
else
service.SendAsync(data);
}
}
@@ -119,7 +187,10 @@ namespace WebSocketSharp.Server {
lock (_syncRoot)
{
foreach (var service in _sessions.Values)
service.SendAsync(data);
if (_isStopped || _isSweeping)
service.Send(data);
else
service.SendAsync(data);
}
}
@@ -132,21 +203,10 @@ namespace WebSocketSharp.Server {
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);
}
}
@@ -166,16 +226,43 @@ namespace WebSocketSharp.Server {
public void Stop(CloseStatusCode code, string reason)
{
stopSweepTimer();
lock (_syncRoot)
{
if (_isStopped)
return;
_isStopped = true;
foreach (var service in _sessions.Values)
foreach (var service in copySessions().Values)
service.Stop(code, reason);
}
}
_sessions.Clear();
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;
}
}

View File

@@ -74,6 +74,20 @@ namespace WebSocketSharp.Server {
#endregion
#region Property
public bool Sweeped {
get {
return _services.Sweeped;
}
set {
_services.Sweeped = value;
}
}
#endregion
#region Private Method
private void init()

View File

@@ -47,9 +47,8 @@ namespace WebSocketSharp.Server {
public WebSocketService()
{
ID = String.Empty;
IsBound = false;
IsStopped = false;
ID = String.Empty;
IsBound = false;
}
#endregion
@@ -72,9 +71,8 @@ namespace WebSocketSharp.Server {
#region Public Properties
public string ID { get; private set; }
public bool IsBound { get; private set; }
public bool IsStopped { get; private set; }
public string ID { get; private set; }
public bool IsBound { get; private set; }
#endregion
@@ -89,8 +87,7 @@ namespace WebSocketSharp.Server {
_socket.OnClose += (sender, e) =>
{
if (!IsStopped)
_sessions.Remove(ID);
_sessions.Remove(ID);
};
}
@@ -202,6 +199,7 @@ namespace WebSocketSharp.Server {
{
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
@@ -211,6 +209,7 @@ namespace WebSocketSharp.Server {
{
Send(data);
};
ThreadPool.QueueUserWorkItem(sendCb);
}
@@ -242,15 +241,22 @@ namespace WebSocketSharp.Server {
public void Stop()
{
Stop(CloseStatusCode.NORMAL, String.Empty);
if (!IsBound)
return;
_socket.Close();
}
public void Stop(CloseStatusCode code, string reason)
{
if (!IsBound || IsStopped)
Stop((ushort)code, reason);
}
public void Stop(ushort code, string reason)
{
if (!IsBound)
return;
IsStopped = true;
_socket.Close(code, reason);
}

View File

@@ -79,7 +79,17 @@ namespace WebSocketSharp.Server {
#endregion
#region Property
#region Properties
public bool Sweeped {
get {
return _sessions.Sweeped;
}
set {
_sessions.Sweeped = value;
}
}
public Uri Uri {
get {

View File

@@ -418,19 +418,19 @@ namespace WebSocketSharp {
return;
}
// Whether a close status code that must not be set for send is used ?
if (!canSendAsCloseFrame(data))
{
onClose(new CloseEventArgs(data));
return;
}
_readyState = WsState.CLOSING;
}
// Whether a close status code that must not be set for send is used ?
if (!canSendAsCloseFrame(data))
{
onClose(new CloseEventArgs(data));
return;
}
closeHandshake(data);
#if DEBUG
Console.WriteLine("WS: Info@close: Exit close method.");
Console.WriteLine("WS: Info@close: Exits close method.");
#endif
}
@@ -451,7 +451,7 @@ namespace WebSocketSharp {
var payloadData = new PayloadData(data.ToArray());
if (payloadData.Length > 125)
{
var msg = "Close frame must have a payload length of 125 bytes or less.";
var msg = "A Close frame must have a payload length of 125 bytes or less.";
onError(msg);
return;
}
@@ -497,10 +497,7 @@ namespace WebSocketSharp {
{
var args = new CloseEventArgs(data);
var frame = createFrame(Fin.FINAL, Opcode.CLOSE, data);
if (send(frame) && !Thread.CurrentThread.IsBackground)
if (!_exitMessageLoop.IsNull())
_exitMessageLoop.WaitOne(5 * 1000);
send(frame);
onClose(args);
}
@@ -738,6 +735,10 @@ namespace WebSocketSharp {
private void onClose(CloseEventArgs eventArgs)
{
if (!Thread.CurrentThread.IsBackground)
if (!_exitMessageLoop.IsNull())
_exitMessageLoop.WaitOne(5 * 1000);
if (closeConnection())
eventArgs.WasClean = true;
@@ -772,7 +773,7 @@ namespace WebSocketSharp {
var buffer = Encoding.UTF8.GetBytes(message);
if (buffer.Length > 125)
{
var msg = "Ping frame must have a payload length of 125 bytes or less.";
var msg = "A Ping frame must have a payload length of 125 bytes or less.";
onError(msg);
return false;
}
@@ -800,7 +801,7 @@ namespace WebSocketSharp {
var frame = _wsStream.ReadFrame();
if (frame.IsNull())
{
var msg = "WebSocket data frame can not be read from network stream.";
var msg = "The WebSocket frame can not be read from network stream.";
close(CloseStatusCode.ABNORMAL, msg);
}
@@ -846,7 +847,7 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.CLOSE)
{// FINAL & CLOSE
#if DEBUG
Console.WriteLine("WS: Info@receive: Start closing handshake.");
Console.WriteLine("WS: Info@receive: Starts closing handshake.");
#endif
close(frame.PayloadData);
return null;
@@ -855,7 +856,7 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.PING)
{// FINAL & PING
#if DEBUG
Console.WriteLine("WS: Info@receive: Return Pong.");
Console.WriteLine("WS: Info@receive: Returns Pong.");
#endif
pong(frame.PayloadData);
return null;
@@ -863,10 +864,14 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.PONG)
{// FINAL & PONG
#if DEBUG
Console.WriteLine("WS: Info@receive: Receives Pong.");
#endif
_receivePong.Set();
return null;
}
// FINAL & (TEXT | BINARY | PONG)
// FINAL & (TEXT | BINARY)
return new MessageEventArgs(frame.Opcode, frame.PayloadData);
}
@@ -889,7 +894,7 @@ namespace WebSocketSharp {
}
#if DEBUG
Console.WriteLine("WS: Info@receiveFragmented: Start closing handshake.");
Console.WriteLine("WS: Info@receiveFragmented: Starts closing handshake.");
#endif
close(CloseStatusCode.INCORRECT_DATA, String.Empty);
return null;
@@ -904,7 +909,7 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.CLOSE)
{// FINAL & CLOSE
#if DEBUG
Console.WriteLine("WS: Info@receiveFragmented: Start closing handshake.");
Console.WriteLine("WS: Info@receiveFragmented: Starts closing handshake.");
#endif
close(frame.PayloadData);
return null;
@@ -913,7 +918,7 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.PING)
{// FINAL & PING
#if DEBUG
Console.WriteLine("WS: Info@receiveFragmented: Return Pong.");
Console.WriteLine("WS: Info@receiveFragmented: Returns Pong.");
#endif
pong(frame.PayloadData);
continue;
@@ -921,14 +926,16 @@ namespace WebSocketSharp {
if (frame.Opcode == Opcode.PONG)
{// FINAL & PONG
#if DEBUG
Console.WriteLine("WS: Info@receiveFragmented: Receives Pong.");
#endif
_receivePong.Set();
OnMessage.Emit(this, new MessageEventArgs(frame.Opcode, frame.PayloadData));
continue;
}
// FINAL & (TEXT | BINARY)
#if DEBUG
Console.WriteLine("WS: Info@receiveFragmented: Start closing handshake.");
Console.WriteLine("WS: Info@receiveFragmented: Starts closing handshake.");
#endif
close(CloseStatusCode.INCORRECT_DATA, String.Empty);
return null;
@@ -964,7 +971,7 @@ namespace WebSocketSharp {
if (_readyState == WsState.CONNECTING ||
_readyState == WsState.CLOSED)
{
var msg = "Connection isn't established or has been closed.";
var msg = "The WebSocket connection isn't established or has been closed.";
onError(msg);
return false;
}
@@ -1011,7 +1018,7 @@ namespace WebSocketSharp {
{
if (_readyState != WsState.OPEN)
{
var msg = "Connection isn't established or has been closed.";
var msg = "The WebSocket connection isn't established or has been closed.";
onError(msg);
return;
}
@@ -1215,7 +1222,7 @@ namespace WebSocketSharp {
{
if (_readyState == WsState.OPEN)
{
Console.WriteLine("WS: Info@Connect: Connection has been established already.");
Console.WriteLine("WS: Info@Connect: The WebSocket connection has been established already.");
return;
}
@@ -1278,7 +1285,9 @@ namespace WebSocketSharp {
if (message.IsNull())
message = String.Empty;
return ping(message, 5 * 1000);
return _isClient
? ping(message, 5 * 1000)
: ping(message, 1 * 1000);
}
/// <summary>

Binary file not shown.