using System; using System.Net; using System.Text; namespace NetCoreServer { /// /// WebSocket server /// /// WebSocket server is used to communicate with clients using WebSocket protocol. Thread-safe. public class WsServer : HttpServer, IWebSocket { internal readonly WebSocket WebSocket; /// /// Initialize WebSocket server with a given IP address and port number /// /// IP address /// Port number public WsServer(IPAddress address, int port) : base(address, port) { WebSocket = new WebSocket(this); } /// /// Initialize WebSocket server with a given IP address and port number /// /// IP address /// Port number public WsServer(string address, int port) : base(address, port) { WebSocket = new WebSocket(this); } /// /// Initialize WebSocket server with a given DNS endpoint /// /// DNS endpoint public WsServer(DnsEndPoint endpoint) : base(endpoint) { WebSocket = new WebSocket(this); } /// /// Initialize WebSocket server with a given IP endpoint /// /// IP endpoint public WsServer(IPEndPoint endpoint) : base(endpoint) { WebSocket = new WebSocket(this); } #region Session management public virtual bool CloseAll() => CloseAll(0, Span.Empty); public virtual bool CloseAll(int status) => CloseAll(status, Span.Empty); public virtual bool CloseAll(int status, string text) => CloseAll(status, Encoding.UTF8.GetBytes(text)); public virtual bool CloseAll(int status, ReadOnlySpan text) => CloseAll(status, Encoding.UTF8.GetBytes(text.ToArray())); public virtual bool CloseAll(int status, byte[] buffer) => CloseAll(status, buffer.AsSpan()); public virtual bool CloseAll(int status, byte[] buffer, long offset, long size) => CloseAll(status, buffer.AsSpan((int)offset, (int)size)); public virtual bool CloseAll(int status, ReadOnlySpan buffer) { lock (WebSocket.WsSendLock) { WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_CLOSE, false, buffer, status); if (!Multicast(WebSocket.WsSendBuffer.AsSpan())) return false; return base.DisconnectAll(); } } #endregion #region Multicasting public override bool Multicast(ReadOnlySpan buffer) { if (!IsStarted) return false; if (buffer.IsEmpty) return true; // Multicast data to all WebSocket sessions foreach (var session in Sessions.Values) { if (session is WsSession wsSession) { if (wsSession.WebSocket.WsHandshaked) wsSession.SendAsync(buffer); } } return true; } #endregion #region WebSocket multicast text methods public bool MulticastText(string text) => MulticastText(Encoding.UTF8.GetBytes(text)); public bool MulticastText(ReadOnlySpan text) => MulticastText(Encoding.UTF8.GetBytes(text.ToArray())); public bool MulticastText(byte[] buffer) => MulticastText(buffer.AsSpan()); public bool MulticastText(byte[] buffer, long offset, long size) => MulticastText(buffer.AsSpan((int)offset, (int)size)); public bool MulticastText(ReadOnlySpan buffer) { lock (WebSocket.WsSendLock) { WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_TEXT, false, buffer); return Multicast(WebSocket.WsSendBuffer.AsSpan()); } } #endregion #region WebSocket multicast binary methods public bool MulticastBinary(string text) => MulticastBinary(Encoding.UTF8.GetBytes(text)); public bool MulticastBinary(ReadOnlySpan text) => MulticastBinary(Encoding.UTF8.GetBytes(text.ToArray())); public bool MulticastBinary(byte[] buffer) => MulticastBinary(buffer.AsSpan()); public bool MulticastBinary(byte[] buffer, long offset, long size) => MulticastBinary(buffer.AsSpan((int)offset, (int)size)); public bool MulticastBinary(ReadOnlySpan buffer) { lock (WebSocket.WsSendLock) { WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_BINARY, false, buffer); return Multicast(WebSocket.WsSendBuffer.AsSpan()); } } #endregion #region WebSocket multicast ping methods public bool MulticastPing(string text) => MulticastPing(Encoding.UTF8.GetBytes(text)); public bool MulticastPing(ReadOnlySpan text) => MulticastPing(Encoding.UTF8.GetBytes(text.ToArray())); public bool MulticastPing(byte[] buffer) => MulticastPing(buffer.AsSpan()); public bool MulticastPing(byte[] buffer, long offset, long size) => MulticastPing(buffer.AsSpan((int)offset, (int)size)); public bool MulticastPing(ReadOnlySpan buffer) { lock (WebSocket.WsSendLock) { WebSocket.PrepareSendFrame(WebSocket.WS_FIN | WebSocket.WS_PING, false, buffer); return Multicast(WebSocket.WsSendBuffer.AsSpan()); } } #endregion protected override TcpSession CreateSession() { return new WsSession(this); } } }