You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

553 lines
20 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
{
/// <summary>
/// MultiClientsWindow.xaml 的交互逻辑
/// </summary>
public partial class TCPWindowV2 : Window
{
public sealed class MySessionClient : TcpSessionClient
{
public Action<ReceivedDataEventArgs> OnMessageReceived { get; set; }
protected override async Task OnTcpReceived(ReceivedDataEventArgs e)
{
//此处逻辑单线程处理。
//此处处理数据功能相当于Received委托
OnMessageReceived?.Invoke(e);
await base.OnTcpReceived(e);
}
}
#region 主界面参数
int currentcount = 0;//目前客户端的数量
List<PanelItem> items = new List<PanelItem>();//客户端组件列表
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<PanelItem>();
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<PanelItem>();
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<NetworkInterface> networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet // 仅以太网
&& nic.OperationalStatus == OperationalStatus.Up); // 仅已启用的接口
CreateListenConnect(networkInterfaces);
while (true)
{
IEnumerable<NetworkInterface> 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<NetworkInterface> 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<int> _excutewithindex;
public LinkCommand(Action action)
{
_excute = action;
}
public LinkCommand(Action<int> action)
{
_excutewithindex = action;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_excute();
}
}
private static List<TagInfo> GetTagInfos(byte[] AutoDealReportData)
{
List<TagInfo> tagInfoList = new List<TagInfo>();
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;
}
/// <summary>
/// 将byte数组转换成十六进制字符串 //e.g. { 0x01, 0x01} ---> " 01 01"
/// </summary>
/// <param name="bytes">byte数组</param>
/// <param name="iLen">数组长度</param>
/// <returns>十六进制字符串</returns>
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<MySessionClient>
{
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);
}
}
}
}