Fixed WebSocketServer

This commit is contained in:
sta 2012-08-06 14:34:39 +09:00
parent 9212716319
commit b730e23248
59 changed files with 277 additions and 124 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,7 +12,7 @@ using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Frame;
namespace Example
namespace Example1
{
public struct NfMessage
{

Binary file not shown.

View File

@ -1,7 +1,7 @@
using System;
using System.Threading;
namespace Example
namespace Example1
{
public class Program
{

Binary file not shown.

Binary file not shown.

Binary file not shown.

14
Example2/Chat.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example2
{
public class Chat : WebSocketService
{
protected override void onMessage(object sender, MessageEventArgs e)
{
Server.Send(e.Data);
}
}
}

14
Example2/Echo.cs Normal file
View File

@ -0,0 +1,14 @@
using System;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example2
{
public class Echo : WebSocketService
{
protected override void onMessage(object sender, MessageEventArgs e)
{
Send(e.Data);
}
}
}

View File

@ -53,6 +53,8 @@
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Program.cs" />
<Compile Include="Echo.cs" />
<Compile Include="Chat.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

Binary file not shown.

View File

@ -1,27 +1,15 @@
using System;
using System.Threading;
using WebSocketSharp;
using WebSocketSharp.Server;
namespace Example
namespace Example2
{
public class Program
{
public static void Main (string[] args)
public static void Main(string[] args)
{
//WebSocketServer wssv = new WebSocketServer("ws://localhost");
WebSocketServer wssv = new WebSocketServer("ws://localhost:4649");
wssv.OnConnection += (sender, e) =>
{
WebSocket ws = e.Socket;
ws.OnMessage += (sender_, e_) =>
{
// Echo
ws.Send(e_.Data);
// Chat
//wssv.Send(e_.Data);
};
};
var wssv = new WebSocketServer<Echo>("ws://localhost:4649");
//var wssv = new WebSocketServer<Chat>("ws://localhost:4649");
wssv.Start();
Console.WriteLine(

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -124,56 +124,56 @@ Type of `code` is `WebSocketSharp.Frame.CloseStatusCode`, type of `reason` is `s
Required namespaces.
using WebSocketSharp;
using WebSocketSharp.Frame;
using WebSocketSharp.Server;
Same as **WebSocket Client**.
`WebSocketServer<T>` class exists in `WebSocketSharp.Server` namespace.
#### Step 2 ####
Creating instance of `WebSocketServer` class.
Creating a class that inherits from `WebSocketService`.
WebSocketServer wssv = new WebSocketServer("ws://example.com:4649");
For example, if you want to provide the echo service,
If you set WebSocket url without port number, `WebSocketServer` set 80 or 443 to port number automatically.
using WebSocketSharp;
using WebSocketSharp.Server;
public class Echo : WebSocketService
{
protected override void onMessage(object sender, MessageEventArgs e)
{
Send(e.Data);
}
}
For example, if you want to provide the chat service,
using WebSocketSharp;
using WebSocketSharp.Server;
public class Chat : WebSocketService
{
protected override void onMessage(object sender, MessageEventArgs e)
{
Server.Send(e.Data);
}
}
#### Step 3 ####
Creating instance of `WebSocketServer<T>` class.
var wssv = new WebSocketServer<Echo>("ws://example.com:4649");
Type of `T` inherits from `WebSocketService` class, so you can use a class that was created in **Step 2**.
If you set WebSocket url without port number, `WebSocketServer<T>` set 80 or 443 to port number automatically.
So it is necessary to run with root permission.
$ sudo mono example2.exe
#### Step 3 ####
#### Step 4 ####
Setting WebSocketServer event handlers.
##### WebSocketServer.OnConnection event #####
`WebSocketServer.OnConnection` event is emitted each time client makes a connection request.
wssv.OnConnection += (sender, e) =>
{
...
};
`WebSocket` to communicate with client is stored in `e.Socket` (`WebSocketSharp.ConnectionEventArgs.Socket`, its type is `WebSocketSharp.WebSocket`), so you operate it.
WebSocket ws = e.Socket;
ws.OnMessage += (sender_, e_) =>
{
...
};
Same settings of `WebSocket` event handlers as **WebSocket Client**.
This WebSocket is server-side, so data is sent from server to client.
If you want to function as echo server that returns a data to client as it is received,
// Echo
ws.Send(e_.Data);
If you want to function as chat server that returns a data to all clients,
// Chat
wssv.Send(e_.Data);
Setting WebSocketServer event handler.
##### WebSocketServer.OnError event #####
@ -186,22 +186,12 @@ If you want to function as chat server that returns a data to all clients,
Error message is stored in `e.Message` (`WebSocketSharp.ErrorEventArgs.Message`, its type is `string`), so you operate it.
#### Step 4 ####
#### Step 5 ####
Starting server.
wssv.Start();
#### Step 5 ####
Sending data to all clients.
wssv.Send(data);
`WebSocketServer.Send` method is overloaded.
`data` types are `string` and `byte[]`.
#### Step 6 ####
Stopping server.

View File

@ -1,10 +1,6 @@
<Properties>
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
<MonoDevelop.Ide.Workbench ActiveDocument="websocket-sharp/WebSocket.cs">
<Files>
<File FileName="websocket-sharp/WebSocket.cs" Line="476" Column="38" />
</Files>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.Workbench />
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>

View File

@ -1,6 +1,6 @@
#region MIT License
/**
* ConnectionEventArgs.cs
* IWebSocketServer.cs
*
* The MIT License
*
@ -27,16 +27,20 @@
#endregion
using System;
using WebSocketSharp.Frame;
namespace WebSocketSharp
namespace WebSocketSharp.Server
{
public class ConnectionEventArgs : EventArgs
public interface IWebSocketServer
{
public WebSocket Socket { get; private set; }
public ConnectionEventArgs(WebSocket webSocket)
{
Socket = webSocket;
}
void AddService(WebSocketService service);
void Close();
void Close(CloseStatusCode code, string reason);
void Ping(string data);
void RemoveService(WebSocketService service);
void Send(byte[] data);
void Send(string data);
void Start();
void Stop();
}
}

View File

@ -37,15 +37,16 @@ using System.Text;
using System.Threading;
using WebSocketSharp.Frame;
namespace WebSocketSharp
namespace WebSocketSharp.Server
{
public class WebSocketServer
public class WebSocketServer<T> : IWebSocketServer
where T : WebSocketService, new()
{
#region Private Fields
private TcpListener _tcpListener;
private Uri _uri;
private SynchronizedCollection<WebSocket> _webSockets;
private SynchronizedCollection<WebSocketService> _services;
private TcpListener _tcpListener;
private Uri _uri;
#endregion
@ -75,8 +76,7 @@ namespace WebSocketSharp
#region Events
public event EventHandler<ConnectionEventArgs> OnConnection;
public event EventHandler<ErrorEventArgs> OnError;
public event EventHandler<ErrorEventArgs> OnError;
#endregion
@ -106,7 +106,7 @@ namespace WebSocketSharp
}
_tcpListener = new TcpListener(IPAddress.Any, port);
_webSockets = new SynchronizedCollection<WebSocket>();
_services = new SynchronizedCollection<WebSocketService>();
}
#endregion
@ -125,12 +125,10 @@ namespace WebSocketSharp
try
{
TcpClient client = listener.EndAcceptTcpClient(ar);
WebSocket ws = new WebSocket(_uri.ToString(), client);
OnConnection.Emit(this, new ConnectionEventArgs(ws));
_webSockets.Add(ws);
ws.Connect();
WebSocket socket = new WebSocket(_uri.ToString(), client);
T service = new T();
service.Bind(this, socket);
service.Open();
}
catch (ObjectDisposedException)
{
@ -170,32 +168,56 @@ namespace WebSocketSharp
#region Public Methods
public void AddService(WebSocketService service)
{
_services.Add(service);
}
public void Close()
{
Close(CloseStatusCode.NORMAL, String.Empty);
}
public void Close(CloseStatusCode code, string reason)
{
lock (_webSockets.SyncRoot)
lock (_services.SyncRoot)
{
foreach (WebSocket ws in _webSockets)
foreach (WebSocketService service in _services)
{
if (ws.ReadyState == WsState.OPEN)
{
ws.Close(code, reason);
}
service.Close(code, reason);
}
}
}
public void Ping(string data)
{
WaitCallback broadcast = (state) =>
{
lock (_services.SyncRoot)
{
foreach (WebSocketService service in _services)
{
service.Ping(data);
}
}
};
ThreadPool.QueueUserWorkItem(broadcast);
}
public void RemoveService(WebSocketService service)
{
_services.Remove(service);
}
public void Send(byte[] data)
{
WaitCallback broadcast = (state) =>
{
lock (_webSockets.SyncRoot)
lock (_services.SyncRoot)
{
foreach (WebSocket ws in _webSockets)
foreach (WebSocketService service in _services)
{
if (ws.ReadyState == WsState.OPEN)
{
ws.Send(data);
}
service.Send(data);
}
}
};
@ -206,14 +228,11 @@ namespace WebSocketSharp
{
WaitCallback broadcast = (state) =>
{
lock (_webSockets.SyncRoot)
lock (_services.SyncRoot)
{
foreach (WebSocket ws in _webSockets)
foreach (WebSocketService service in _services)
{
if (ws.ReadyState == WsState.OPEN)
{
ws.Send(data);
}
service.Send(data);
}
}
};
@ -229,7 +248,7 @@ namespace WebSocketSharp
public void Stop()
{
_tcpListener.Stop();
Close(CloseStatusCode.NORMAL, String.Empty);
Close();
}
#endregion

View File

@ -0,0 +1,130 @@
#region MIT License
/**
* WebSocketService.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.Server
{
public abstract class WebSocketService
{
#region Properties
public IWebSocketServer Server { get; private set; }
public WebSocket Socket { get; private set; }
#endregion
#region Public Constructor
public WebSocketService()
{
}
#endregion
#region Private Method
private void defaultBind()
{
Socket.OnOpen += (sender, e) =>
{
Server.AddService(this);
};
}
#endregion
#region Protected Methods
protected virtual void onOpen(object sender, EventArgs e)
{
}
protected virtual void onMessage(object sender, MessageEventArgs e)
{
}
protected virtual void onError(object sender, ErrorEventArgs e)
{
}
protected virtual void onClose(object sender, CloseEventArgs e)
{
Server.RemoveService(this);
}
#endregion
#region Public Methods
public void Bind(IWebSocketServer server, WebSocket socket)
{
Server = server;
Socket = socket;
defaultBind();
Socket.OnOpen += onOpen;
Socket.OnMessage += onMessage;
Socket.OnError += onError;
Socket.OnClose += onClose;
}
public void Close()
{
Socket.Close();
}
public void Close(CloseStatusCode code, string reason)
{
Socket.Close(code, reason);
}
public void Open()
{
Socket.Connect();
}
public void Ping(string data)
{
Socket.Ping(data);
}
public void Send(byte[] data)
{
Socket.Send(data);
}
public void Send(string data)
{
Socket.Send(data);
}
#endregion
}
}

View File

@ -748,16 +748,10 @@ namespace WebSocketSharp
private void messageLoop()
{
#if DEBUG
Console.WriteLine("\nWS: Info@messageLoop: Current thread IsBackground?: {0}", Thread.CurrentThread.IsBackground);
#endif
while (_readyState == WsState.OPEN)
{
message();
}
#if DEBUG
Console.WriteLine("WS: Info@messageLoop: Exit messageLoop method.");
#endif
}
private void startMessageThread()

View File

@ -72,14 +72,16 @@
<Compile Include="Frame\Opcode.cs" />
<Compile Include="Frame\PayloadData.cs" />
<Compile Include="Frame\Rsv.cs" />
<Compile Include="ConnectionEventArgs.cs" />
<Compile Include="ErrorEventArgs.cs" />
<Compile Include="WebSocketServer.cs" />
<Compile Include="WebSocket.cs" />
<Compile Include="Server\IWebSocketServer.cs" />
<Compile Include="Server\WebSocketServer.cs" />
<Compile Include="Server\WebSocketService.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="Stream\" />
<Folder Include="Frame\" />
<Folder Include="Server\" />
</ItemGroup>
</Project>

Binary file not shown.