using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; namespace JiLinApp.Docking.VibrateAlarm; public class AsyncTcpServer : IDisposable { #region Fields private TcpListener Listener { get; set; } private ConcurrentDictionary Clients { get; } #region Properties /// /// 监听的IP地址 /// public IPAddress Address { get; private set; } /// /// 监听的端口 /// public int Port { get; private set; } /// /// 通信使用的编码 /// public Encoding Encoding { get; set; } public bool Disposed { get; private set; } #endregion Properties #endregion Fields #region Ctors private byte[] InOptionValues { get; set; } /// /// 异步TCP服务器 /// /// 监听的端口 public AsyncTcpServer(int port) : this(IPAddress.Any, port) { } /// /// 异步TCP服务器 /// /// 监听的终结点 public AsyncTcpServer(IPEndPoint ipep) : this(ipep.Address, ipep.Port) { } /// /// 异步TCP服务器 /// /// 监听的IP地址 /// 监听的端口 public AsyncTcpServer(IPAddress address, int port) { uint dummy = 0; InOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; BitConverter.GetBytes((uint)1).CopyTo(InOptionValues, 0); BitConverter.GetBytes((uint)1000).CopyTo(InOptionValues, Marshal.SizeOf(dummy)); BitConverter.GetBytes((uint)1000).CopyTo(InOptionValues, Marshal.SizeOf(dummy) * 2); Address = address; Port = port; Encoding = Encoding.Default; Listener = new(address, port); Clients = new(); Listener.AllowNatTraversal(true); } ~AsyncTcpServer() { Stop(); } #endregion Ctors #region Server /// /// 启动服务器 /// /// 异步TCP服务器 public void Start() { Start(30); } /// /// 启动服务器 /// /// 服务器所允许的挂起连接序列的最大长度 /// 异步TCP服务器 public void Start(int backlog) { if (IsRunning()) return; Listener.Start(backlog); AcceptTcpClient(Listener); } /// /// 停止服务器 /// /// 异步TCP服务器 public void Stop() { if (!IsRunning()) return; try { Listener.Stop(); } finally { foreach (var client in Clients.Values) { client.TcpClient.Client.Disconnect(false); } Clients.Clear(); } } public bool IsRunning() { return Listener != null && Listener.Server.IsBound; } public ICollection GetAllClient() { return Clients.Values; } #endregion Server #region Events /// /// 与客户端的连接已建立事件 /// public event EventHandler? ClientConnected; /// /// 与客户端的连接已断开事件 /// public event EventHandler? ClientDisconnected; /// /// 接收到数据报文事件 /// public event EventHandler>? DatagramReceived; private void RaiseClientConnected(TcpClient client) { ClientConnected?.Invoke(this, new TcpClientConnectedEventArgs(client)); } private void RaiseClientDisconnected(TcpClient client) { ClientDisconnected?.Invoke(this, new TcpClientDisconnectedEventArgs(client)); } private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) { DatagramReceived?.Invoke(this, new TcpDatagramReceivedEventArgs(sender, datagram)); } #endregion Events #region Receive private void AcceptTcpClient(TcpListener listener) { listener.BeginAcceptTcpClient(HandleTcpClientAccepted, listener); } private void ReadBuffer(TcpClientState internalClient, NetworkStream networkStream) { networkStream.BeginRead(internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); } private void HandleTcpClientAccepted(IAsyncResult ar) { if (!IsRunning()) return; TcpListener? listener; TcpClient? client; try { listener = ar.AsyncState as TcpListener; client = listener?.EndAcceptTcpClient(ar); client?.Client.IOControl(IOControlCode.KeepAliveValues, InOptionValues, null); } catch (Exception) { throw; } if (listener == null || client == null || !client.Connected) return; byte[] buffer = new byte[client.ReceiveBufferSize]; TcpClientState internalClient = new(client, buffer); // add client connection to cache string clientKey = client.Client.RemoteEndPoint?.ToString() ?? ""; if (clientKey == "") return; Clients.AddOrUpdate(clientKey, internalClient, (n, o) => { return internalClient; }); RaiseClientConnected(client); // begin to read data try { NetworkStream networkStream = internalClient.NetworkStream; ReadBuffer(internalClient, networkStream); } catch (Exception) { Clients.TryRemove(clientKey, out _); RaiseClientDisconnected(internalClient.TcpClient); return; } // keep listening to accept next connection AcceptTcpClient(listener); } private void HandleDatagramReceived(IAsyncResult ar) { if (!IsRunning()) return; TcpClientState? internalClient = ar.AsyncState as TcpClientState; if (internalClient == null) return; string clientKey = internalClient.TcpClient.Client.RemoteEndPoint?.ToString() ?? ""; if (clientKey == "") return; if (!internalClient.TcpClient.Connected) { // connection has been closed Clients.TryRemove(clientKey, out _); RaiseClientDisconnected(internalClient.TcpClient); } NetworkStream networkStream; int readBytesNum; try { networkStream = internalClient.NetworkStream; // if the remote host has shutdown its connection, // read will immediately return with zero bytes. readBytesNum = networkStream.EndRead(ar); } catch (Exception) { return; } if (readBytesNum == 0) { // connection has been closed Clients.TryRemove(clientKey, out _); RaiseClientDisconnected(internalClient.TcpClient); return; } // received byte and trigger event notification byte[] receivedBytes = new byte[readBytesNum]; Buffer.BlockCopy(internalClient.Buffer, 0, receivedBytes, 0, readBytesNum); RaiseDatagramReceived(internalClient, receivedBytes); // continue listening for tcp datagram packets ReadBuffer(internalClient, networkStream); } #endregion Receive #region Send /// /// 发送报文至指定的客户端 /// /// 客户端 /// 报文 public void Send(TcpClient tcpClient, byte[] datagram) { if (!IsRunning()) return; if (tcpClient == null || !tcpClient.Connected || datagram == null) return; try { NetworkStream stream = tcpClient.GetStream(); if (stream.CanWrite) { stream.Write(datagram, 0, datagram.Length); } } catch (Exception) { } } /// /// 发送报文至指定的客户端 /// /// 客户端 /// 报文 public void Send(TcpClient tcpClient, string datagram) { Send(tcpClient, Encoding.GetBytes(datagram)); } /// /// 发送报文至所有客户端 /// /// 报文 public void SendToAll(byte[] datagram) { if (!IsRunning()) return; foreach (var client in Clients.Values) { Send(client.TcpClient, datagram); } } /// /// 发送报文至所有客户端 /// /// 报文 public void SendToAll(string datagram) { if (!IsRunning()) return; SendToAll(Encoding.GetBytes(datagram)); } /// /// 发送报文至指定的客户端 /// /// 客户端 /// 报文 public void SendAsync(TcpClient tcpClient, byte[] datagram) { if (!IsRunning()) return; if (tcpClient == null || !tcpClient.Connected || datagram == null) return; try { NetworkStream stream = tcpClient.GetStream(); if (stream.CanWrite) { stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); } } catch (Exception) { } } /// /// 发送报文至指定的客户端 /// /// 客户端 /// 报文 public void SendAsync(TcpClient tcpClient, string datagram) { SendAsync(tcpClient, Encoding.GetBytes(datagram)); } /// /// 发送报文至所有客户端 /// /// 报文 public void SendToAllAsync(byte[] datagram) { if (!IsRunning()) return; foreach (var client in Clients.Values) { SendAsync(client.TcpClient, datagram); } } /// /// 发送报文至所有客户端 /// /// 报文 public void SendToAllAsync(string datagram) { if (!IsRunning()) return; SendToAllAsync(Encoding.GetBytes(datagram)); } private void HandleDatagramWritten(IAsyncResult ar) { try { (ar.AsyncState as TcpClient)?.GetStream().EndWrite(ar); } catch (Exception) { } } #endregion Send #region IDisposable Members /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; /// false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (!Disposed) { if (disposing) Stop(); Disposed = true; } } #endregion IDisposable Members }