using CommunityToolkit.Mvvm.ComponentModel;
|
using System.Collections.ObjectModel;
|
using System.Globalization;
|
using System.Text;
|
using System.Text.RegularExpressions;
|
using System.Windows;
|
using System.Windows.Controls;
|
using System.Windows.Data;
|
using System.Windows.Documents;
|
using System.Windows.Media;
|
using TouchSocket.Core;
|
using TouchSocket.Sockets;
|
using UtilLib;
|
|
namespace Plugin.UICollection
|
{
|
public enum DataType
|
{
|
String = 0,
|
HEX = 1
|
}
|
|
public enum SupportEncode
|
{
|
GBK = 0,
|
ASCII = 1,
|
UTF8 = 2
|
}
|
|
public class EndMarkSource
|
{
|
public string Name { get; set; }
|
public int Type { get; set; }
|
}
|
|
public class ByteStringConverter : IValueConverter
|
{
|
private TcpDebugger control { get; set; }
|
|
public ByteStringConverter(TcpDebugger control)
|
{
|
this.control = control;
|
}
|
|
public static string GroupByTwo(string str)
|
{
|
if (string.IsNullOrEmpty(str))
|
return string.Empty;
|
|
StringBuilder result = new StringBuilder();
|
for (int i = 0; i < str.Length; i += 2)
|
{
|
if (i > 0)
|
result.Append(' ');
|
|
int length = Math.Min(2, str.Length - i);
|
result.Append(str.Substring(i, length));
|
}
|
return result.ToString();
|
}
|
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
DataType sendType = control.SendDataType;
|
if (sendType != DataType.HEX)
|
{
|
return value;
|
}
|
var str = value.ToString();
|
return GroupByTwo(str);
|
}
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
DataType sendType = control.SendDataType;
|
if (sendType != DataType.HEX)
|
{
|
return value;
|
}
|
return value.ToString().Replace(" ", "");
|
}
|
}
|
|
/// <summary>
|
/// TcpDebugger.xaml 的交互逻辑
|
/// </summary>
|
[ObservableObject]
|
public partial class TcpDebugger : UserControl
|
{
|
|
[ObservableProperty]
|
private string ip = "127.0.0.1";
|
|
[ObservableProperty]
|
private int port;
|
|
[ObservableProperty]
|
private int clientPort;
|
|
[ObservableProperty]
|
private DataType receiveDataType = DataType.String;
|
|
[ObservableProperty]
|
private DataType sendDataType = DataType.String;
|
|
[ObservableProperty]
|
private bool isConnected = false;
|
|
[ObservableProperty]
|
private string sendText;
|
|
[ObservableProperty]
|
private SupportEncode receiveEncode;
|
|
[ObservableProperty]
|
private SupportEncode sendEncode;
|
|
[ObservableProperty]
|
private ObservableCollection<EndMarkSource> endMarkSource = new ObservableCollection<EndMarkSource> {
|
new EndMarkSource{ Name="无",Type=-1},
|
new EndMarkSource{ Name="\\r",Type=0},
|
new EndMarkSource{ Name="\\r\\n",Type=1},
|
new EndMarkSource{ Name="自定义",Type=2},
|
};
|
|
[ObservableProperty]
|
private int endMark;
|
|
[ObservableProperty]
|
private string customEndMark;
|
|
private ByteStringConverter bsConverter;
|
|
|
private TcpClient client;
|
|
public TcpDebugger()
|
{
|
DataContext = this;
|
InitializeComponent();
|
sendEncodeInput.ItemsSource = Enum.GetValues(typeof(SupportEncode)).Cast<SupportEncode>();
|
receiveEncodeInput.ItemsSource = Enum.GetValues(typeof(SupportEncode)).Cast<SupportEncode>();
|
DataObject.AddPastingHandler(sendBox, OnPasting);
|
bsConverter = new ByteStringConverter(this);
|
BindingOperations.SetBinding(sendBox, TextBox.TextProperty, new Binding(nameof(SendText))
|
{
|
Source = this,
|
Mode = BindingMode.TwoWay,
|
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
|
Converter = bsConverter
|
});
|
}
|
|
private void Button_Click(object sender, RoutedEventArgs e)
|
{
|
var btn = (Button)sender;
|
if (btn.Tag.ToString() == "Connect")
|
{
|
TryConnect();
|
return;
|
}
|
|
if (btn.Tag.ToString() == "Send")
|
{
|
TrySend();
|
return;
|
}
|
|
}
|
|
private void TryConnect()
|
{
|
try
|
{
|
if (IsConnected) return;
|
var config = new TouchSocketConfig().SetRemoteIPHost($"tcp://{Ip}:{Port}");
|
client = new TcpClient();
|
client.Received = TcpReceived;
|
client.Connected = (sender, e) =>
|
{
|
Dispatcher.Invoke(() =>
|
{
|
Add("连接", "连接成功", Brushes.Green);
|
IsConnected = true;
|
});
|
return EasyTask.CompletedTask;
|
};
|
client.Closed = (sender, e) =>
|
{
|
Dispatcher.Invoke(() =>
|
{
|
Add("连接", "连接断开", Brushes.Red);
|
IsConnected = false;
|
});
|
return EasyTask.CompletedTask;
|
};
|
client.SetupAsync(config);
|
client.ConnectAsync();
|
}
|
catch (Exception ex)
|
{
|
IsConnected = false;
|
// throw ex;
|
}
|
}
|
|
private Task TcpReceived(object sender, ReceivedDataEventArgs e)
|
{
|
try
|
{
|
var datas = e.Memory.Span.ToArray();
|
string msg = null;
|
if (ReceiveDataType == DataType.HEX)
|
{
|
msg = HexUtil.ByteArrayToHex(datas);
|
}
|
else
|
{
|
if (ReceiveEncode == SupportEncode.GBK)
|
{
|
msg = Encoding.Default.GetString(datas);
|
}
|
else if (ReceiveEncode == SupportEncode.ASCII)
|
{
|
msg = Encoding.ASCII.GetString(datas);
|
}
|
else
|
{
|
|
msg = Encoding.UTF8.GetString(datas);
|
}
|
}
|
Add("接收", msg, Brushes.Green);
|
}
|
catch (Exception ex)
|
{
|
//log.Error($"TcpReceived Error.", ex);
|
}
|
return EasyTask.CompletedTask;
|
}
|
|
private byte[] GetBytes(out string msg)
|
{
|
msg = null;
|
if (string.IsNullOrEmpty(SendText))
|
{
|
return null;
|
}
|
if (SendDataType == DataType.String)
|
{
|
msg = SendText + GetEndMark();
|
if (SendEncode == SupportEncode.GBK)
|
{
|
return Encoding.Default.GetBytes(msg);
|
}
|
if (SendEncode == SupportEncode.ASCII)
|
{
|
return Encoding.ASCII.GetBytes(msg);
|
}
|
if (SendEncode == SupportEncode.UTF8)
|
{
|
return Encoding.UTF8.GetBytes(msg);
|
}
|
return null;
|
}
|
msg = SendText;
|
if (msg.Length % 2 != 0)
|
{
|
msg = msg.Insert(msg.Length - 1, "0");
|
}
|
msg = ByteStringConverter.GroupByTwo(msg);
|
return HexUtil.HexToByteArray(msg);
|
}
|
|
private string GetEndMark()
|
{
|
if (EndMark == -1)
|
{
|
return string.Empty;
|
}
|
if (EndMark == 0)
|
{
|
return "\r";
|
}
|
if (EndMark == 1)
|
{
|
return "\r\n";
|
}
|
if (EndMark == 2)
|
{
|
return CustomEndMark;
|
}
|
return string.Empty;
|
}
|
|
public void TrySend()
|
{
|
if (!IsConnected)
|
{
|
MessageBox.Show("请先连接", "提示");
|
return;
|
}
|
var datas = GetBytes(out string msg);
|
if (datas != null)
|
{
|
client.SendAsync(datas).Wait();
|
Add("发送", msg, Brushes.Blue);
|
// SendText = string.Empty;
|
}
|
}
|
|
public void Add(string type, string text, Brush color)
|
{
|
Dispatcher.BeginInvoke(() =>
|
{
|
string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
Run run = new Run();
|
run.Text = $"{time} {type}\r\n";
|
run.Foreground = Brushes.Gray;
|
|
Paragraph paragraph = new Paragraph(run)
|
{
|
LineHeight = 1
|
};
|
|
run = new Run();
|
run.Text = $"{text}\r\n";
|
run.Foreground = color;
|
paragraph.Inlines.Add(run);
|
//也可以插入到最后面
|
console.Document.Blocks.InsertAfter(console.Document.Blocks.LastBlock, paragraph);
|
|
//插入到最前面
|
//rtxtLog.Document.Blocks.Add(paragraph);
|
|
// 滚动至最后行
|
//rtxtLog.ScrollToEnd();
|
//Console.ScrollToHome();
|
console.ScrollToEnd();
|
// 删除
|
//if (Console.Document.Blocks.Count > 10000)
|
//{
|
// for (int i = 1000; i < Console.Document.Blocks.Count; i++)
|
// {
|
// _ = Console.Document.Blocks.Remove(Console.Document.Blocks.FirstBlock);
|
// }
|
//}
|
|
}, System.Windows.Threading.DispatcherPriority.Normal);
|
}
|
|
private static readonly Regex HexRegex = new Regex("^[0-9A-Fa-f]+$");
|
|
private void TextBox_PreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
|
{
|
if (SendDataType != DataType.HEX)
|
{
|
return;
|
}
|
var tb = (TextBox)sender;
|
string segment = e.Text;
|
|
if (!HexRegex.IsMatch(segment))
|
{
|
tb.Text = tb.Text.Replace(segment, "");
|
tb.CaretIndex = tb.Text.Length;
|
e.Handled = true;
|
return;
|
}
|
// tb.Text = tb.Text.ToUpper();
|
|
base.OnPreviewTextInput(e);
|
}
|
|
private void OnPasting(object sender, DataObjectPastingEventArgs e)
|
{
|
if (SendDataType != DataType.HEX)
|
{
|
return;
|
}
|
|
if (e.DataObject.GetDataPresent(typeof(string)))
|
{
|
string text = (string)e.DataObject.GetData(typeof(string));
|
text = text.Replace(" ", "");
|
if (!HexRegex.IsMatch(text))
|
{
|
e.CancelCommand();
|
}
|
}
|
}
|
}
|
}
|