#if !NET20 using Apewer; using System; using System.Collections.Generic; namespace Apewer.WebSocket { /// public sealed class GenericServer : IDisposable { const string DefaultAddress = "0.0.0.0"; const ushort DefaultPort = 8000; private Dictionary _connections = new Dictionary(); private WebSocketServer _server = null; private bool _running = false; private string _address = null; private int _port = DefaultPort; /// public event SocketEvent OnOpen; /// public event SocketEvent OnClose; /// public event SocketEvent OnMessage; /// public event SocketEvent OnBytes; /// public event SocketEvent OnPing; /// public event SocketEvent OnPong; /// public event SocketEvent OnError; /// public event ServerEvent Excepted; #region Properties /// 正在监听。 public bool Running { get { return _running; } } /// 监听的地址。 public string Address { get { return _address; } } /// 监听的端口号。 public int Port { get { return _port; } } /// 当前 Sockets 数量。 public int Count { get { var count = 0; lock (_connections) { count = _connections.Count; } return count; } } #endregion #region Methods /// public GenericServer() { } /// 关闭服务,并释放系统资源。 public void Dispose() { lock (_connections) { _connections.Clear(); } lock (_server) { if (_server != null) { _server.Dispose(); } } _server = null; _running = false; } /// 启动监听,如果监听正在运行则失败。 public bool Start(int port = DefaultPort, string address = DefaultAddress) { if (address == null) return false; if (_running) return false; _address = address ?? ""; _port = NumberUtility.Restrict( port, 0, ushort.MaxValue); try { var location = "ws://" + address + ":" + port.ToString(); _server = new WebSocketServer(location); _server.Start(Initialize); _running = true; return true; } catch (Exception exception) { RaiseExcepted(exception); return false; } } /// 对所有连接发送文本。 /// public int Send(params char[] message) { var text = null as string; if (message == null || message.Length < 1) return 0; if (message.Length == 1) { text = message[0].ToString(); } else { var sb = new System.Text.StringBuilder(); foreach (var i in message) { if ((object)i != null) sb.Append(i); } text = sb.ToString(); } if (text.Length < 1) return 0; var connections = GetConnections(); var count = 0; foreach (var connection in connections) { try { var sent = connection.Send(message); if (sent != null) count += 1; } catch (Exception exception) { RaiseExcepted(exception); } } return count; } /// 发送文本。 /// public int Send(params string[] message) { var text = null as string; if (message == null || message.Length < 1) return 0; if (message.Length == 1) { text = message[0].ToString(); } else { var sb = new System.Text.StringBuilder(); foreach (var i in message) { if (i != null) sb.Append(i); } text = sb.ToString(); } if (text.Length < 1) return 0; var connections = GetConnections(); var count = 0; foreach (var connection in connections) { try { var sent = connection.Send(message); if (sent != null) count += 1; } catch (Exception exception) { RaiseExcepted(exception); } } return count; } /// 发送字节数组。 /// public int Send(params byte[] message) { var connections = GetConnections(); var count = 0; foreach (var connection in connections) { try { var sent = connection.Send(message); if (sent != null) count += 1; } catch (Exception exception) { RaiseExcepted(exception); } } return count; } /// 发送 PING。 /// public int Ping(params byte[] message) { var connections = GetConnections(); var count = 0; foreach (var connection in connections) { try { var sent = connection.Ping(message); if (sent != null) count += 1; } catch (Exception exception) { RaiseExcepted(exception); } } return count; } /// 发送 PONG。 /// public int Pong(params byte[] message) { var connections = GetConnections(); var count = 0; foreach (var connection in connections) { try { var sent = connection.Pong(message); if (sent != null) count += 1; } catch (Exception exception) { RaiseExcepted(exception); } } return count; } /// 关闭 Socket 连接。 public void Close() { lock (_server) { try { if (_server != null && _server.ListenerSocket != null) { _server.ListenerSocket.Close(); } } catch (Exception exception) { RaiseExcepted(exception); } } } #endregion #region Private List GetConnections() { var list = new List(); lock (_connections) { foreach (var i in _connections.Values) { if (i != null) list.Add(i); } } return list; } void RaiseExcepted(Exception exception) { if (exception == null) return; if (Excepted == null) return; try { InBackground(() => Excepted(this, exception)); } catch { } } void Initialize(Connection socket) { if (socket == null) return; socket.OnOpen = () => InBackground(() => { var hashcode = socket.GetHashCode(); lock (_connections) { if (!_connections.ContainsKey(hashcode)) { _connections.Add(hashcode, socket); } } try { OnOpen?.Invoke(socket); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnClose = () => InBackground(() => { var hashcode = socket.GetHashCode(); try { OnClose?.Invoke(socket); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnBytes = (content) => InBackground(() => { try { OnBytes?.Invoke(socket, content); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnError = (content) => InBackground(() => { try { OnError?.Invoke(socket, content); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnMessage = (content) => InBackground(() => { try { OnMessage?.Invoke(socket, content); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnPing = (content) => InBackground(() => { try { if (OnPing == null) socket.Pong(content); else OnPing?.Invoke(socket, content); } catch (Exception exception) { RaiseExcepted(exception); } }); socket.OnPong = (content) => InBackground(() => { try { OnPong?.Invoke(socket, content); } catch (Exception exception) { RaiseExcepted(exception); } }); } int GetHashCode(Connection connection) { if (connection == null) return 0; if (connection.ConnectionInfo == null) return 0; return connection.ConnectionInfo.Id.GetHashCode(); } #endregion #region static /// public static LogLevel LogLevel { get { return WebSocketLog.Level; } set { WebSocketLog.Level = value; } } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] private static void InBackground(System.Action action) { if (action == null) return; var thread = new System.Threading.Thread(delegate (object v) { ((System.Action)v)(); }); thread.IsBackground = true; thread.Start(action); } #endregion } } #endif