using System; using System.Buffers.Text; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.Eventing.Reader; using System.IO; using System.IO.Ports; using System.Linq; using System.Net.NetworkInformation; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Remoting.Messaging; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Xml; using Google.Protobuf.WellKnownTypes; using K4os.Compression.LZ4.Streams.Abstractions; using Mesnac.Log; using Microsoft.Xaml.Behaviors.Core; using Mysqlx.Crud; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.Encoders; using TouchSocket.Core; using TouchSocket.Sockets; using ZstdSharp.Unsafe; using static SocketExample.MyTouchClass; namespace SocketExample { /// /// MultiClientsWindow.xaml 的交互逻辑 /// public partial class TCPWindowV2 : Window { public sealed class MySessionClient : TcpSessionClient { public Action OnMessageReceived { get; set; } protected override async Task OnTcpReceived(ReceivedDataEventArgs e) { //此处逻辑单线程处理。 //此处处理数据,功能相当于Received委托 OnMessageReceived?.Invoke(e); await base.OnTcpReceived(e); } } #region 主界面参数 int currentcount = 0;//目前客户端的数量 List items = new List();//客户端组件列表 public static double? WindowLeft { get; set; } public static double? WindowTop { get; set; } public static double? WindowWidth { get; set; } public static double? WindowHeight { get; set; } public static WindowState? OriginWindowState { get; set; } public static int? Buttonflag { get; set; } public TCPWindowV2() { InitializeComponent(); EnsureFolderExists("日志文件夹"); this.Closing += TCPWindowV2_Closing; PanelContainer.ItemsSource = items; SaveWindowSettings(); Buttonflag = 0; } #endregion //结束所有线程,防止心跳线程冗余 private void TCPWindowV2_Closing(object sender, CancelEventArgs e) { System.Environment.Exit(0); } #region 主界面按钮事件 private void GenerateButton_Click(object sender, RoutedEventArgs e)//添加客户端框体 { if (int.TryParse(CountTextBox.Text, out int count) && count > 0) { //var items = new List(); for (int i = 0; i < count; i++) { items.Add(new PanelItem(i + currentcount)); } currentcount += count; PanelContainer.ItemsSource = null;//刷新 PanelContainer.ItemsSource = items; } else { MessageBox.Show("请输入有效的正整数", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } Welcome_StackPanel.Visibility = Visibility.Visible; NewTerminal_StackPanel.Visibility = Visibility.Collapsed; } private void Shutdown_Button_Click(object sender, RoutedEventArgs e) { Application.Current.Shutdown(); } private void CreateTerminal_Button_Click(object sender, RoutedEventArgs e) { Welcome_StackPanel.Visibility = Visibility.Collapsed; NewTerminal_StackPanel.Visibility = Visibility.Visible; } private void Maxmize_Button_Click(object sender, RoutedEventArgs e) { if (Buttonflag == 0) { this.WindowState = WindowState.Maximized; MaxMinImage.Source = new BitmapImage(new Uri(@"/取消全屏.png", UriKind.Relative)); Buttonflag = 1; } else { LoadWindowSettings(); MaxMinImage.Source = new BitmapImage(new Uri(@"/全屏.png", UriKind.Relative)); Buttonflag = 0; } } private void Minimize_Button_Click(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; } private void ClearButton_Click(object sender, RoutedEventArgs e)//清空客户端 { foreach (PanelItem item in items) { item.dispose(); item.Sessiondispose(); } items = new List(); PanelContainer.ItemsSource = null; currentcount = 0; } private void ListenButton_Click(object sender, RoutedEventArgs e) { Thread ListeningPortThread = new Thread(ListeningTheard); ListeningPortThread.IsBackground = true; ListeningPortThread.Start(); Welcome_StackPanel.Visibility = Visibility.Visible; NewTerminal_StackPanel.Visibility = Visibility.Collapsed; } #endregion #region 其他功能 private void ListeningTheard() //监听线程 { IEnumerable networkInterfaces = NetworkInterface.GetAllNetworkInterfaces() .Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet // 仅以太网 && nic.OperationalStatus == OperationalStatus.Up); // 仅已启用的接口 CreateListenConnect(networkInterfaces); while (true) { IEnumerable NewnetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces() .Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet // 仅以太网 && nic.OperationalStatus == OperationalStatus.Up); // 仅已启用的接口 var UniquenetworkInterfaces = NewnetworkInterfaces .Where(newNic => !networkInterfaces.Any(oldNic => oldNic.Id == newNic.Id)) .ToList(); if (!UniquenetworkInterfaces.Any()) { Thread.Sleep(1000); continue; } networkInterfaces = NewnetworkInterfaces; CreateListenConnect(UniquenetworkInterfaces); } } private void CreateListenConnect(IEnumerable networkInterfaces) //创建连接 { foreach (var nic in networkInterfaces) { var ipProperties = nic.GetIPProperties(); var unicastAddresses = ipProperties.UnicastAddresses .Where(addr => addr.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork); foreach (var addr in unicastAddresses) { var tcpService = new MyService(); tcpService.SetupAsync(new TouchSocketConfig()//载入配置 .SetListenIPHosts($"tcp://{addr.Address}:20108", 7790)//可以同时监听两个地址 .ConfigureContainer(a =>//容器的配置顺序应该在最前面 { a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用) }) .ConfigurePlugins(a => { //a.Add();//此处可以添加插件 })); tcpService.Connected += ListeningConnected; tcpService.Closed += ListeningClosed; tcpService.StartAsync(); Console.WriteLine($"网卡: {nic.Description}, IP: {addr.Address}"); MessageBox.Show($"{addr.Address}监听成功!"); } } } private Task ListeningConnected(MySessionClient client, ConnectedEventArgs e) //连接事件 { Application.Current.Dispatcher.Invoke(() => { items.Add(new PanelItem(client)); PanelContainer.ItemsSource = null; PanelContainer.ItemsSource = items; }); return EasyTask.CompletedTask; } private Task ListeningClosed(MySessionClient client, ClosedEventArgs e) //断开事件 { try { Application.Current.Dispatcher.Invoke(() => { foreach (PanelItem item in items) { if (item.SessionID.Equals(client.Id)) { try { item.Sessiondispose(); items.Remove(item); PanelContainer.ItemsSource = null; PanelContainer.ItemsSource = items; if (items.Count == 0) break; } catch (Exception ex) { MessageBox.Show(ex.Message); } } } }); }catch(Exception ex) { Console.WriteLine(ex.Message); } return EasyTask.CompletedTask; } public class LinkCommand : ICommand //command方法实现 { private Action _excute; private Action _excutewithindex; public LinkCommand(Action action) { _excute = action; } public LinkCommand(Action action) { _excutewithindex = action; } public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { _excute(); } } private static List GetTagInfos(byte[] AutoDealReportData) { List tagInfoList = new List(); try { int iFirstCountPos = 6; //第一次读取标签次数位置 int iFirstRSSIPos = 7; //第一次读取标签强度位置 int iFirstAnt = 8; int iFirstPC = 9; //第一次读取标签天线位置 int iFirstLeftBarcketPos = 11;//EPC数据起始位置 UInt16 tempDataCount = 0; int tempDataRSSI = 0; UInt16 tempDataANT = 0; int iBarcodeGroupCount = Convert.ToInt32(AutoDealReportData[5].ToString()); //标签组数 int iBarcodeLength = 16; //标签长度 int iCommonSecondFlag = 0; int dataLength = Convert.ToInt32(AutoDealReportData[2].ToString()); for (int j = 0; j < iBarcodeGroupCount; j++) { TagInfo tag = new TagInfo(); byte[] tempPCByte = new byte[2]; //取出PC Array.Clear(tempPCByte, 0, 2); Array.Copy(AutoDealReportData, iFirstPC, tempPCByte, 0, 2); //PC转二进制取前五位转十进制 int epcLength = Convert.ToInt32(Convert.ToString(Convert.ToInt64(tempPCByte[0].ToString("X"), 16), 2).PadLeft(8, '0').Substring(0, 5), 2) * 2; iBarcodeLength = epcLength; byte[] tempDataByte = new byte[epcLength]; Array.Clear(tempDataByte, 0, iBarcodeLength); Array.Copy(AutoDealReportData, iFirstLeftBarcketPos, tempDataByte, 0, iBarcodeLength); byte[] tempCountByte = new byte[1]; //取出标签次数 Array.Clear(tempCountByte, 0, 1); Array.Copy(AutoDealReportData, iFirstCountPos, tempCountByte, 0, 1); tempDataCount = tempCountByte[0]; byte[] tempRSSIByte = new byte[1]; //取出标签强度 Array.Clear(tempRSSIByte, 0, 1); Array.Copy(AutoDealReportData, iFirstRSSIPos, tempRSSIByte, 0, 1); tempDataRSSI = HexStringToNegative(bytesToHexStr(tempRSSIByte, 1)); #region add by wenjy 20220829 取出天线号 byte[] tempAntByte = new byte[1]; //取出天线号 Array.Clear(tempAntByte, 0, 1); Array.Copy(AutoDealReportData, iFirstAnt, tempAntByte, 0, 1); tempDataANT = tempAntByte[0]; #endregion tag.Count = tempDataCount; tag.RSSI = tempDataRSSI; tag.EPC = tempDataByte; tag.EPCstring = System.Text.Encoding.ASCII.GetString(tempDataByte); tag.PC = tempPCByte; tag.Antana = tempDataANT; tagInfoList.Add(tag); int iBarcodeListLen = tagInfoList.Count; //特别注意,必须这样,要不然会多一条数据 iFirstCountPos = iFirstCountPos + iBarcodeLength + 5; //次数 iFirstRSSIPos = iFirstCountPos + 1; //强度 iFirstAnt = iFirstRSSIPos + 1; //天线 iFirstPC = iFirstAnt + 1; iFirstLeftBarcketPos = iFirstLeftBarcketPos + iBarcodeLength + 5; iCommonSecondFlag++; if (iCommonSecondFlag == iBarcodeGroupCount) { //mutauto.ReleaseMutex(); return tagInfoList; } } } catch (Exception ex) { //LogInfo.Info("----函数调用:Device_AutoDealContent 自动处理函数异常:" + ex.ToString()); //mutauto.ReleaseMutex(); } return tagInfoList; } public static int HexStringToNegative(string strNumber) { int iNegate = 0; int iNumber = Convert.ToInt32(strNumber, 16); if (iNumber > 127) { int iComplement = iNumber - 1; string strNegate = string.Empty; char[] binchar = Convert.ToString(iComplement, 2).PadLeft(8, '0').ToArray(); foreach (char ch in binchar) { if (Convert.ToInt32(ch) == 48) { strNegate += "1"; } else { strNegate += "0"; } } iNegate = -Convert.ToInt32(strNegate, 2); } return iNegate; } public class TagInfo { public byte[] PC = new byte[2]; public int Count; public int RSSI; public int Antana; public byte[] EPC; public byte[] Data; public string PCstring = null; public string EPCstring = null; public DateTime Time; } /// /// 将byte数组转换成十六进制字符串 //e.g. { 0x01, 0x01} ---> " 01 01" /// /// byte数组 /// 数组长度 /// 十六进制字符串 public static string bytesToHexStr(byte[] bytes, int iLen) { string returnStr = ""; if (bytes != null) { for (int i = 0; i < iLen; i++) { returnStr += bytes[i].ToString("X2"); } } return returnStr; } private static void EnsureFolderExists(string folderPath) { // 检查指定的文件夹路径对应的文件夹是否已经存在 if (!Directory.Exists(folderPath)) { try { // 如果文件夹不存在,则尝试创建该文件夹 Directory.CreateDirectory(folderPath); } catch (IOException ex) { // 如果在创建文件夹过程中出现IOException异常(比如权限不足、磁盘已满等原因导致无法创建文件夹) // 这里通过消息框向用户展示创建文件夹失败的异常信息,方便用户知晓问题所在 MessageBox.Show($"创建文件夹 {folderPath} 失败,异常信息: {ex.Message}"); // 重新抛出异常,让调用这个方法的上层代码知道创建文件夹出现了问题,以便进行进一步的处理,比如终止程序或者尝试其他恢复操作 throw; } } } private static void EnsureTxtExists(string txtPath, string MachineName, string IPinfo, string Portinfo) { // 检查指定的txt路径对应的txt是否已经存在 if (!File.Exists(txtPath)) { try { StreamWriter streamWriter = new StreamWriter(txtPath, true); streamWriter.WriteLineAsync($"设备名称:{MachineName}\nIP地址:{IPinfo}\n端口号:{Portinfo}\n____________________________"); streamWriter.Close(); } catch (IOException ex) { // 如果在创建文件夹过程中出现IOException异常(比如权限不足、磁盘已满等原因导致无法创建文件夹) // 这里通过消息框向用户展示创建文件夹失败的异常信息,方便用户知晓问题所在 MessageBox.Show($"创建txt {txtPath} 失败,异常信息: {ex.Message}"); // 重新抛出异常,让调用这个方法的上层代码知道创建文件夹出现了问题,以便进行进一步的处理,比如终止程序或者尝试其他恢复操作 throw; } } } private void Border_MouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) { this.DragMove(); } } private void LoadWindowSettings() { if (WindowLeft.HasValue && WindowTop.HasValue) { this.Left = WindowLeft.Value; this.Top = WindowTop.Value; } if (WindowWidth.HasValue && WindowHeight.HasValue) { this.Width = WindowWidth.Value; this.Height = WindowHeight.Value; } if (OriginWindowState.HasValue) { this.WindowState = OriginWindowState.Value; } } private void SaveWindowSettings() { WindowLeft = this.Left; WindowTop = this.Top; WindowWidth = this.Width; WindowHeight = this.Height; OriginWindowState = this.WindowState; } #endregion public class MyService : TcpService { protected override void LoadConfig(TouchSocketConfig config) { //此处加载配置,用户可以从配置中获取配置项。 base.LoadConfig(config); } protected override MySessionClient NewClient() { return new MySessionClient(); } protected override async Task OnTcpConnecting(MySessionClient socketClient, ConnectingEventArgs e) { //此处逻辑会多线程处理。 //e.Id:对新连接的客户端进行ID初始化,默认情况下是按照设定的规则随机分配的。 //但是按照需求,您可以自定义设置,例如设置为其IP地址。但是需要注意的是id必须在生命周期内唯一。 //e.IsPermitOperation:指示是否允许该客户端链接。 await base.OnTcpConnecting(socketClient, e); } } } }