|
@ -1,7 +1,6 @@ |
|
|
using System.Collections.Concurrent; |
|
|
using System.Collections.Concurrent; |
|
|
using System.Net; |
|
|
using System.Net; |
|
|
using System.Net.Sockets; |
|
|
using System.Net.Sockets; |
|
|
using System.Runtime.InteropServices; |
|
|
|
|
|
using System.Text; |
|
|
using System.Text; |
|
|
|
|
|
|
|
|
namespace JiLinApp.Docking.VibrateAlarm; |
|
|
namespace JiLinApp.Docking.VibrateAlarm; |
|
@ -39,8 +38,6 @@ public class AsyncTcpServer : IDisposable |
|
|
|
|
|
|
|
|
#region Ctors
|
|
|
#region Ctors
|
|
|
|
|
|
|
|
|
private byte[] InOptionValues { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 异步TCP服务器
|
|
|
/// 异步TCP服务器
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
@ -64,11 +61,6 @@ public class AsyncTcpServer : IDisposable |
|
|
/// <param name="port">监听的端口</param>
|
|
|
/// <param name="port">监听的端口</param>
|
|
|
public AsyncTcpServer(IPAddress address, int port) |
|
|
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; |
|
|
Address = address; |
|
|
Port = port; |
|
|
Port = port; |
|
|
Encoding = Encoding.Default; |
|
|
Encoding = Encoding.Default; |
|
@ -157,15 +149,19 @@ public class AsyncTcpServer : IDisposable |
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>>? DatagramReceived; |
|
|
public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>>? DatagramReceived; |
|
|
|
|
|
|
|
|
private void RaiseClientConnected(TcpClient client) |
|
|
private void RaiseClientConnected(string clientKey, TcpClientState clientState) |
|
|
{ |
|
|
{ |
|
|
ClientConnected?.Invoke(this, new TcpClientConnectedEventArgs(client)); |
|
|
Clients.AddOrUpdate(clientKey, clientState, (n, o) => { return clientState; }); |
|
|
|
|
|
ClientConnected?.Invoke(this, new TcpClientConnectedEventArgs(clientState.TcpClient)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void RaiseClientDisconnected(TcpClient client) |
|
|
private void RaiseClientDisconnected(string clientKey, TcpClient client) |
|
|
|
|
|
{ |
|
|
|
|
|
if (Clients.TryRemove(clientKey, out _)) |
|
|
{ |
|
|
{ |
|
|
ClientDisconnected?.Invoke(this, new TcpClientDisconnectedEventArgs(client)); |
|
|
ClientDisconnected?.Invoke(this, new TcpClientDisconnectedEventArgs(client)); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) |
|
|
private void RaiseDatagramReceived(TcpClientState sender, byte[] datagram) |
|
|
{ |
|
|
{ |
|
@ -181,11 +177,6 @@ public class AsyncTcpServer : IDisposable |
|
|
listener.BeginAcceptTcpClient(HandleTcpClientAccepted, 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) |
|
|
private void HandleTcpClientAccepted(IAsyncResult ar) |
|
|
{ |
|
|
{ |
|
|
if (!IsRunning()) return; |
|
|
if (!IsRunning()) return; |
|
@ -195,7 +186,6 @@ public class AsyncTcpServer : IDisposable |
|
|
{ |
|
|
{ |
|
|
listener = ar.AsyncState as TcpListener; |
|
|
listener = ar.AsyncState as TcpListener; |
|
|
client = listener?.EndAcceptTcpClient(ar); |
|
|
client = listener?.EndAcceptTcpClient(ar); |
|
|
client?.Client.IOControl(IOControlCode.KeepAliveValues, InOptionValues, null); |
|
|
|
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
@ -204,24 +194,22 @@ public class AsyncTcpServer : IDisposable |
|
|
if (listener == null || client == null || !client.Connected) return; |
|
|
if (listener == null || client == null || !client.Connected) return; |
|
|
|
|
|
|
|
|
byte[] buffer = new byte[client.ReceiveBufferSize]; |
|
|
byte[] buffer = new byte[client.ReceiveBufferSize]; |
|
|
TcpClientState internalClient = new(client, buffer); |
|
|
TcpClientState clientState = new(client, buffer); |
|
|
|
|
|
|
|
|
// add client connection to cache
|
|
|
// add client connection to cache
|
|
|
string clientKey = client.Client.RemoteEndPoint?.ToString() ?? ""; |
|
|
string clientKey = client.Client.RemoteEndPoint?.ToString() ?? ""; |
|
|
if (clientKey == "") return; |
|
|
if (clientKey == "") return; |
|
|
Clients.AddOrUpdate(clientKey, internalClient, (n, o) => { return internalClient; }); |
|
|
RaiseClientConnected(clientKey, clientState); |
|
|
RaiseClientConnected(client); |
|
|
|
|
|
|
|
|
|
|
|
// begin to read data
|
|
|
// begin to read data
|
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
NetworkStream networkStream = internalClient.NetworkStream; |
|
|
NetworkStream networkStream = clientState.NetworkStream; |
|
|
ReadBuffer(internalClient, networkStream); |
|
|
ReadBuffer(clientState, networkStream); |
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
Clients.TryRemove(clientKey, out _); |
|
|
RaiseClientDisconnected(clientKey, clientState.TcpClient); |
|
|
RaiseClientDisconnected(internalClient.TcpClient); |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -229,6 +217,11 @@ public class AsyncTcpServer : IDisposable |
|
|
AcceptTcpClient(listener); |
|
|
AcceptTcpClient(listener); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void ReadBuffer(TcpClientState clientState, NetworkStream networkStream) |
|
|
|
|
|
{ |
|
|
|
|
|
networkStream.BeginRead(clientState.Buffer, 0, clientState.Buffer.Length, HandleDatagramReceived, clientState); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private void HandleDatagramReceived(IAsyncResult ar) |
|
|
private void HandleDatagramReceived(IAsyncResult ar) |
|
|
{ |
|
|
{ |
|
|
if (!IsRunning()) return; |
|
|
if (!IsRunning()) return; |
|
@ -239,8 +232,7 @@ public class AsyncTcpServer : IDisposable |
|
|
if (!internalClient.TcpClient.Connected) |
|
|
if (!internalClient.TcpClient.Connected) |
|
|
{ |
|
|
{ |
|
|
// connection has been closed
|
|
|
// connection has been closed
|
|
|
Clients.TryRemove(clientKey, out _); |
|
|
RaiseClientDisconnected(clientKey, internalClient.TcpClient); |
|
|
RaiseClientDisconnected(internalClient.TcpClient); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
NetworkStream networkStream; |
|
|
NetworkStream networkStream; |
|
@ -254,13 +246,13 @@ public class AsyncTcpServer : IDisposable |
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
|
|
|
RaiseClientDisconnected(clientKey, internalClient.TcpClient); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
if (readBytesNum == 0) |
|
|
if (readBytesNum == 0) |
|
|
{ |
|
|
{ |
|
|
// connection has been closed
|
|
|
// connection has been closed
|
|
|
Clients.TryRemove(clientKey, out _); |
|
|
RaiseClientDisconnected(clientKey, internalClient.TcpClient); |
|
|
RaiseClientDisconnected(internalClient.TcpClient); |
|
|
|
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -280,15 +272,15 @@ public class AsyncTcpServer : IDisposable |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="tcpClient">客户端</param>
|
|
|
/// <param name="client">客户端</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
public void Send(TcpClient tcpClient, byte[] datagram) |
|
|
public void Send(TcpClient client, byte[] datagram) |
|
|
{ |
|
|
{ |
|
|
if (!IsRunning()) return; |
|
|
if (!IsRunning()) return; |
|
|
if (tcpClient == null || !tcpClient.Connected || datagram == null) return; |
|
|
if (client == null || !client.Connected || datagram == null) return; |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
NetworkStream stream = tcpClient.GetStream(); |
|
|
NetworkStream stream = client.GetStream(); |
|
|
if (stream.CanWrite) |
|
|
if (stream.CanWrite) |
|
|
{ |
|
|
{ |
|
|
stream.Write(datagram, 0, datagram.Length); |
|
|
stream.Write(datagram, 0, datagram.Length); |
|
@ -296,17 +288,20 @@ public class AsyncTcpServer : IDisposable |
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
|
|
|
string clientKey = client.Client.RemoteEndPoint?.ToString() ?? ""; |
|
|
|
|
|
if (clientKey == "") return; |
|
|
|
|
|
if (client != null) RaiseClientDisconnected(clientKey, client); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="tcpClient">客户端</param>
|
|
|
/// <param name="client">客户端</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
public void Send(TcpClient tcpClient, string datagram) |
|
|
public void Send(TcpClient client, string datagram) |
|
|
{ |
|
|
{ |
|
|
Send(tcpClient, Encoding.GetBytes(datagram)); |
|
|
Send(client, Encoding.GetBytes(datagram)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
@ -335,33 +330,36 @@ public class AsyncTcpServer : IDisposable |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="tcpClient">客户端</param>
|
|
|
/// <param name="client">客户端</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
public void SendAsync(TcpClient tcpClient, byte[] datagram) |
|
|
public void SendAsync(TcpClient client, byte[] datagram) |
|
|
{ |
|
|
{ |
|
|
if (!IsRunning()) return; |
|
|
if (!IsRunning()) return; |
|
|
if (tcpClient == null || !tcpClient.Connected || datagram == null) return; |
|
|
if (client == null || !client.Connected || datagram == null) return; |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
NetworkStream stream = tcpClient.GetStream(); |
|
|
NetworkStream stream = client.GetStream(); |
|
|
if (stream.CanWrite) |
|
|
if (stream.CanWrite) |
|
|
{ |
|
|
{ |
|
|
stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); |
|
|
stream.BeginWrite(datagram, 0, datagram.Length, HandleDatagramWritten, client); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
|
|
|
string clientKey = client.Client.RemoteEndPoint?.ToString() ?? ""; |
|
|
|
|
|
if (clientKey == "") return; |
|
|
|
|
|
if (client != null) RaiseClientDisconnected(clientKey, client); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// 发送报文至指定的客户端
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
/// <param name="tcpClient">客户端</param>
|
|
|
/// <param name="client">客户端</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
/// <param name="datagram">报文</param>
|
|
|
public void SendAsync(TcpClient tcpClient, string datagram) |
|
|
public void SendAsync(TcpClient client, string datagram) |
|
|
{ |
|
|
{ |
|
|
SendAsync(tcpClient, Encoding.GetBytes(datagram)); |
|
|
SendAsync(client, Encoding.GetBytes(datagram)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
@ -389,12 +387,17 @@ public class AsyncTcpServer : IDisposable |
|
|
|
|
|
|
|
|
private void HandleDatagramWritten(IAsyncResult ar) |
|
|
private void HandleDatagramWritten(IAsyncResult ar) |
|
|
{ |
|
|
{ |
|
|
|
|
|
TcpClient? client = null; |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
(ar.AsyncState as TcpClient)?.GetStream().EndWrite(ar); |
|
|
client = ar.AsyncState as TcpClient; |
|
|
|
|
|
client?.GetStream().EndWrite(ar); |
|
|
} |
|
|
} |
|
|
catch (Exception) |
|
|
catch (Exception) |
|
|
{ |
|
|
{ |
|
|
|
|
|
string clientKey = client?.Client.RemoteEndPoint?.ToString() ?? ""; |
|
|
|
|
|
if (clientKey == "") return; |
|
|
|
|
|
if (client != null) RaiseClientDisconnected(clientKey, client); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|