|
|
@@ -0,0 +1,515 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
+using System.Linq;
|
|
|
+using System.Net;
|
|
|
+using System.Runtime.CompilerServices;
|
|
|
+using System.Text;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using Toolkit.Log4;
|
|
|
+using TouchSocket.Core;
|
|
|
+using TouchSocket.Sockets;
|
|
|
+
|
|
|
+namespace Toolkit.Tcp
|
|
|
+{
|
|
|
+ public class ClientCommunicate : INotifyPropertyChanged
|
|
|
+ {
|
|
|
+ private IWaitingClient<TouchSocket.Sockets.TcpClient> WaitClient;
|
|
|
+ private bool isFirstConnect = true;
|
|
|
+ private Task bgConnectTask;
|
|
|
+ public event Action<Guid, object, ConnectedEventArgs> ConnectedEvent;
|
|
|
+ public event Action<Guid, object, DisconnectEventArgs> DisconnectedEvent;
|
|
|
+ public event Action<Guid, object, ReceivedDataEventArgs> ReceivedEvent;
|
|
|
+ public event Action<Guid, object, string> SendEvent;
|
|
|
+
|
|
|
+ #region 属性
|
|
|
+ public TcpService TcpService { get; private set; }
|
|
|
+ public TcpClient TcpClient { get; private set; }
|
|
|
+
|
|
|
+ public Guid Id { get; set; }
|
|
|
+
|
|
|
+ public int Port { get; private set; }
|
|
|
+
|
|
|
+ public string Ip { get; private set; }
|
|
|
+
|
|
|
+ public Terminator Terminator { get; private set; }
|
|
|
+
|
|
|
+ public DataEncoding DataEncoding { get; private set; }
|
|
|
+
|
|
|
+ public bool IsConnected
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ return TcpClient.Online;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public int Timeout { get; set; } = 5000;
|
|
|
+
|
|
|
+ private bool _CanExecute = false;
|
|
|
+
|
|
|
+ public bool CanExecute
|
|
|
+ {
|
|
|
+ get { return _CanExecute; }
|
|
|
+ set { SetProperty(ref _CanExecute, value); }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+
|
|
|
+ public ClientCommunicate()
|
|
|
+ {
|
|
|
+ Id = Guid.NewGuid();
|
|
|
+ Ip = "127.0.0.1";//192.168.2.99
|
|
|
+ Port = 8888;
|
|
|
+ Terminator = Terminator.None;
|
|
|
+ DataEncoding = DataEncoding.UTF8;
|
|
|
+ //主站做服务器
|
|
|
+ TcpClient = new TouchSocket.Sockets.TcpClient();
|
|
|
+ var config = new TouchSocketConfig();
|
|
|
+ config.SetRemoteIPHost(new IPHost(IPAddress.Parse(Ip), Port));
|
|
|
+ config.ConfigurePlugins(a => { a.UseReconnection(-1, true, 1000); }); ////如需永远尝试连接,tryCount设置为-1即可。
|
|
|
+
|
|
|
+ ////设置结束符
|
|
|
+ if ( Terminator == Terminator.None )
|
|
|
+ {
|
|
|
+ config.SetTcpDataHandlingAdapter(() => { return new FixedHeaderPackageAdapter() { FixedHeaderType= FixedHeaderType.Int }; }); ////亦或者省略\r\n,但此时调用方不能高速调用,会粘包
|
|
|
+ }
|
|
|
+ else if ( Terminator == Terminator.CR )
|
|
|
+ {
|
|
|
+ config.SetTcpDataHandlingAdapter(() => { return new TerminatorPackageAdapter("\r"); }); //命令行中使用\r结尾
|
|
|
+ }
|
|
|
+ else if ( Terminator == Terminator.LF )
|
|
|
+ {
|
|
|
+ config.SetTcpDataHandlingAdapter(() => { return new TerminatorPackageAdapter("\n"); }); //命令行中使用\n结尾
|
|
|
+ }
|
|
|
+ else if ( Terminator == Terminator.CRLF )
|
|
|
+ {
|
|
|
+ config.SetTcpDataHandlingAdapter(() => { return new TerminatorPackageAdapter("\r\n"); }); //命令行中使用\r\n结尾
|
|
|
+ }
|
|
|
+ //载入配置
|
|
|
+ TcpClient.Setup(config);
|
|
|
+ ////调用CreateWaitingClient获取到IWaitingClient的对象。
|
|
|
+ WaitClient = TcpClient.CreateWaitingClient(new WaitingOptions()
|
|
|
+ {
|
|
|
+ FilterFunc = response => //设置用于筛选的fun委托,当返回为true时,才会响应返回
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+
|
|
|
+ //if (response.Data.Length == 1)
|
|
|
+ //{
|
|
|
+ // return true;
|
|
|
+ //}
|
|
|
+ //return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //成功连接到服务器
|
|
|
+ TcpClient.Connected = ConnectedVoid;
|
|
|
+ //有客户端断开连接
|
|
|
+ TcpClient.Disconnected = DisconnectedVoid;
|
|
|
+ //从客户端收到信息
|
|
|
+ TcpClient.Received = ReceivedVoid;
|
|
|
+ }
|
|
|
+
|
|
|
+ #region 事件接收
|
|
|
+ //---------------------------------------------客户端--------------------------------------------
|
|
|
+ /// <summary>
|
|
|
+ /// 连接到服务器时
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <param name="e"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private Task ConnectedVoid(ITcpClient client, ConnectedEventArgs e)
|
|
|
+ {
|
|
|
+ CanExecute = true;
|
|
|
+ ConnectedEvent?.Invoke(this.Id, client, e);
|
|
|
+ return EasyTask.CompletedTask;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 有客户端断开连接
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <param name="e"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private Task DisconnectedVoid(ITcpClientBase client, DisconnectEventArgs e)
|
|
|
+ {
|
|
|
+ CanExecute = false;
|
|
|
+ DisconnectedEvent?.Invoke(this.Id, client, e);
|
|
|
+ return EasyTask.CompletedTask;
|
|
|
+ }
|
|
|
+ /// <summary>
|
|
|
+ /// 从客户端收到信息
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="client"></param>
|
|
|
+ /// <param name="e"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private Task ReceivedVoid(ITcpClient client, ReceivedDataEventArgs e)
|
|
|
+ {
|
|
|
+
|
|
|
+ ReceivedEvent?.Invoke(this.Id, client, e );
|
|
|
+ return EasyTask.CompletedTask;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 连接
|
|
|
+ public void Connect()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ TcpClient.Connect();
|
|
|
+ isFirstConnect = false;
|
|
|
+ }
|
|
|
+ catch ( Exception )
|
|
|
+ {
|
|
|
+ if ( bgConnectTask == null )
|
|
|
+ {
|
|
|
+ bgConnectTask = Task.Run(async () =>
|
|
|
+ {
|
|
|
+ while ( true )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ TcpClient.Connect();
|
|
|
+ isFirstConnect = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ catch ( Exception )
|
|
|
+ {
|
|
|
+ await Task.Delay(1000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ throw;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task ConnectAsync()
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ await TcpClient.ConnectAsync();
|
|
|
+ LogHelper.Info(Ip+" 打印机连接成功");
|
|
|
+ isFirstConnect = false;
|
|
|
+ }
|
|
|
+ catch ( Exception )
|
|
|
+ {
|
|
|
+ if ( bgConnectTask == null )
|
|
|
+ {
|
|
|
+ bgConnectTask = Task.Run(async () =>
|
|
|
+ {
|
|
|
+ while ( true )
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ TcpClient.Connect();
|
|
|
+ isFirstConnect = false;
|
|
|
+ LogHelper.Info(Ip + "打印机连接成功");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ catch ( Exception )
|
|
|
+ {
|
|
|
+ LogHelper.Info(Ip + "打印机连接失败");
|
|
|
+ await Task.Delay(500);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ throw;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Disconnect()
|
|
|
+ {
|
|
|
+ if ( TcpClient != null )
|
|
|
+ {
|
|
|
+ TcpClient.Close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Dispose()
|
|
|
+ {
|
|
|
+ if ( TcpClient != null )
|
|
|
+ {
|
|
|
+ TcpClient.Dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 控制
|
|
|
+
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 收发数据
|
|
|
+ /// <summary>
|
|
|
+ /// 发送并接收数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="send"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string SendAndReceive(string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, WaitClient.Client, send);
|
|
|
+ var returnData = WaitClient.SendThenReturn(encoding.GetBytes(send), Timeout);
|
|
|
+ ReceivedDataEventArgs receivedDataEvent = new ReceivedDataEventArgs(new ByteBlock(returnData), null);
|
|
|
+ ReceivedEvent?.Invoke(this.Id, WaitClient, receivedDataEvent);
|
|
|
+ return encoding.GetString(returnData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 发送并接收数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="send"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public byte[] SendAndReceive(byte[] send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ //SendEvent?.Invoke(this.Id, WaitClient.Client, send);
|
|
|
+ var returnData = WaitClient.SendThenReturn(send, Timeout);
|
|
|
+ ReceivedDataEventArgs receivedDataEvent = new ReceivedDataEventArgs(new ByteBlock(returnData), null);
|
|
|
+ ReceivedEvent?.Invoke(this.Id, WaitClient, receivedDataEvent);
|
|
|
+ return returnData;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 发送并接收数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="send"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> SendAndReceiveAsync(string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, WaitClient.Client, send);
|
|
|
+ var returnData = await WaitClient.SendThenReturnAsync(encoding.GetBytes(send), Timeout);
|
|
|
+ ReceivedDataEventArgs receivedDataEvent = new ReceivedDataEventArgs(new ByteBlock(returnData), null);
|
|
|
+ ReceivedEvent?.Invoke(this.Id, WaitClient, receivedDataEvent);
|
|
|
+ return encoding.GetString(returnData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 发送并接收数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="send"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public string SendAndReceive(SocketClient client, string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, WaitClient.Client, send);
|
|
|
+ var returnData = WaitClient.SendThenReturn(encoding.GetBytes(send), Timeout);
|
|
|
+ ReceivedDataEventArgs receivedDataEvent = new ReceivedDataEventArgs(new ByteBlock(returnData), null);
|
|
|
+ ReceivedEvent?.Invoke(this.Id, WaitClient, receivedDataEvent);
|
|
|
+ return encoding.GetString(returnData);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 发送并接收数据
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="send"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public async Task<string> SendAndReceiveAsync(SocketClient client, string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, WaitClient.Client, send);
|
|
|
+ var returnData = await WaitClient.SendThenReturnAsync(encoding.GetBytes(send), Timeout);
|
|
|
+ ReceivedDataEventArgs receivedDataEvent = new ReceivedDataEventArgs(new ByteBlock(returnData), null);
|
|
|
+ ReceivedEvent?.Invoke(this.Id, WaitClient, receivedDataEvent);
|
|
|
+ return encoding.GetString(returnData);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Send(string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ //byte[]sendbuff= encoding.GetBytes(send);
|
|
|
+ //int size = sendbuff.Length;
|
|
|
+ //byte[] datasize = new byte[4];
|
|
|
+ //datasize = BitConverter.GetBytes(size);
|
|
|
+
|
|
|
+ //byte[] mergedData = datasize.Concat(sendbuff).ToArray();
|
|
|
+ //SendEvent?.Invoke(this.Id, TcpClient, send);
|
|
|
+ TcpClient.Send(encoding.GetBytes(send));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Send(byte []send)
|
|
|
+ {
|
|
|
+ //int size = send.Length;
|
|
|
+ //byte[] datasize = new byte[4];
|
|
|
+ //datasize = BitConverter.GetBytes(size);
|
|
|
+
|
|
|
+ //byte[] mergedData = datasize.Concat(send).ToArray();
|
|
|
+
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, TcpClient,encoding.GetString(send));
|
|
|
+ TcpClient.Send(send);
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task SendAsync(string send)
|
|
|
+ {
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, TcpClient, send);
|
|
|
+ await TcpClient.SendAsync(encoding.GetBytes(send));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Send(SocketClient client, string send)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if ( client == null )
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, TcpClient, send);
|
|
|
+ TcpClient.Send(encoding.GetBytes(send));
|
|
|
+ }
|
|
|
+ catch ( Exception ex )
|
|
|
+ {
|
|
|
+ LogHelper.error.Error("发送数据时出错", ex);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public async Task SendAsync(SocketClient client, string send)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if ( client == null )
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Encoding encoding = GetEncoding();
|
|
|
+ SendEvent?.Invoke(this.Id, TcpClient, send);
|
|
|
+ await TcpClient.SendAsync(encoding.GetBytes(send));
|
|
|
+ }
|
|
|
+ catch ( Exception ex )
|
|
|
+ {
|
|
|
+ LogHelper.error.Error("发送数据时出错", ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取编码
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dataEncoding"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ public Encoding GetEncoding()
|
|
|
+ {
|
|
|
+ DataEncoding dataEncoding = this.DataEncoding;
|
|
|
+ Encoding encoding;
|
|
|
+ if ( dataEncoding == DataEncoding.Default )
|
|
|
+ {
|
|
|
+ encoding = Encoding.Default;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.ASCII )
|
|
|
+ {
|
|
|
+ encoding = Encoding.ASCII;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.UTF7 )
|
|
|
+ {
|
|
|
+ encoding = Encoding.UTF7;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.UTF8 )
|
|
|
+ {
|
|
|
+ encoding = Encoding.UTF8;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.UTF32 )
|
|
|
+ {
|
|
|
+ encoding = Encoding.UTF32;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.Unicode )
|
|
|
+ {
|
|
|
+ encoding = Encoding.Unicode;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.BigEndianUnicode )
|
|
|
+ {
|
|
|
+ encoding = Encoding.BigEndianUnicode;
|
|
|
+ }
|
|
|
+ else if ( dataEncoding == DataEncoding.GB2312 )
|
|
|
+ {
|
|
|
+
|
|
|
+ encoding = Encoding.GetEncoding("gb2312");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ encoding = Encoding.Default;
|
|
|
+ }
|
|
|
+ return encoding;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 属性通知
|
|
|
+ /// <summary>
|
|
|
+ /// Occurs when a property value changes.
|
|
|
+ /// </summary>
|
|
|
+ public event PropertyChangedEventHandler PropertyChanged;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Checks if a property already matches a desired value. Sets the property and
|
|
|
+ /// notifies listeners only when necessary.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T">Type of the property.</typeparam>
|
|
|
+ /// <param name="storage">Reference to a property with both getter and setter.</param>
|
|
|
+ /// <param name="value">Desired value for the property.</param>
|
|
|
+ /// <param name="propertyName">Name of the property used to notify listeners. This
|
|
|
+ /// value is optional and can be provided automatically when invoked from compilers that
|
|
|
+ /// support CallerMemberName.</param>
|
|
|
+ /// <returns>True if the value was changed, false if the existing value matched the
|
|
|
+ /// desired value.</returns>
|
|
|
+ protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
|
|
|
+ {
|
|
|
+ if ( EqualityComparer<T>.Default.Equals(storage, value) ) return false;
|
|
|
+
|
|
|
+ storage = value;
|
|
|
+ RaisePropertyChanged(propertyName);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Checks if a property already matches a desired value. Sets the property and
|
|
|
+ /// notifies listeners only when necessary.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T">Type of the property.</typeparam>
|
|
|
+ /// <param name="storage">Reference to a property with both getter and setter.</param>
|
|
|
+ /// <param name="value">Desired value for the property.</param>
|
|
|
+ /// <param name="propertyName">Name of the property used to notify listeners. This
|
|
|
+ /// value is optional and can be provided automatically when invoked from compilers that
|
|
|
+ /// support CallerMemberName.</param>
|
|
|
+ /// <param name="onChanged">Action that is called after the property value has been changed.</param>
|
|
|
+ /// <returns>True if the value was changed, false if the existing value matched the
|
|
|
+ /// desired value.</returns>
|
|
|
+ protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
|
|
|
+ {
|
|
|
+ if ( EqualityComparer<T>.Default.Equals(storage, value) ) return false;
|
|
|
+
|
|
|
+ storage = value;
|
|
|
+ onChanged?.Invoke();
|
|
|
+ RaisePropertyChanged(propertyName);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Raises this object's PropertyChanged event.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="propertyName">Name of the property used to notify listeners. This
|
|
|
+ /// value is optional and can be provided automatically when invoked from compilers
|
|
|
+ /// that support <see cref="CallerMemberNameAttribute"/>.</param>
|
|
|
+ protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
|
|
|
+ {
|
|
|
+ OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Raises this object's PropertyChanged event.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="args">The PropertyChangedEventArgs</param>
|
|
|
+ protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
|
|
|
+ {
|
|
|
+ PropertyChanged?.Invoke(this, args);
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ }
|
|
|
+}
|