同系列文章:
源代码
FrServerWindow.xaml
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Splash" x:Class="Splash.FrServerWindow" mc:Ignorable="d" Title="汉王人证比对服务器端 By 秦建辉" Height="480" Width="400" Icon="dog.ico" FontSize="16" SizeToContent="Height" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded" ResizeMode="NoResize" Closing="Window_Closing"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <GroupBox Grid.Row="0" Header="设置" Margin="4"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Margin="4" Content="服务器地址"/> <Label Grid.Row="1" Grid.Column="0" Margin="4" Content="服务器端口"/> <ComboBox Grid.Row="0" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" x:Name="comboBoxServerIP"/> <TextBox Grid.Row="1" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" x:Name="textBoxServerPort" Text="50052"/> </Grid> </GroupBox> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Button Grid.Column="0" Margin="4" Width="128" Padding="8" Content="重置" x:Name="buttonReset" Click="ButtonReset_Click"/> <Button Grid.Column="1" Margin="4" Width="128" Padding="8" Content="开启服务" x:Name="buttonService" Click="ButtonService_Click"/> </Grid> <GroupBox Grid.Row="2" Header="统计" Margin="4"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Margin="4" Content="服务访问数"/> <Label Grid.Row="1" Grid.Column="0" Margin="4" Content="图像处理数"/> <Label Grid.Row="2" Grid.Column="0" Margin="4" Content="比对成功数"/> <Label Grid.Row="3" Grid.Column="0" Margin="4" Content="比对失败数"/> <Label Grid.Row="4" Grid.Column="0" Margin="4" Content="比对异常数"/> <TextBox Grid.Row="0" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" IsReadOnly="True" x:Name="textBoxService" Text="{Binding CountService, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:FrServerWindow}}}"/> <TextBox Grid.Row="1" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" IsReadOnly="True" x:Name="textBoxAll" Text="{Binding CountAll, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:FrServerWindow}}}"/> <TextBox Grid.Row="2" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" IsReadOnly="True" x:Name="textBoxPass" Text="{Binding CountPass, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:FrServerWindow}}}"/> <TextBox Grid.Row="3" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" IsReadOnly="True" x:Name="textBoxDeny" Text="{Binding CountDeny, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:FrServerWindow}}}"/> <TextBox Grid.Row="4" Grid.Column="1" VerticalContentAlignment="Center" Margin="4" IsReadOnly="True" x:Name="textBoxException" Text="{Binding CountException, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:FrServerWindow}}}"/> </Grid> </GroupBox> </Grid> </Window>
FrServerWindow.xaml.cs
/* ---------------------------------------------------------- * 文件名称:FrServerWindow.xaml.cs * 作者:秦建辉 * * 微信:splashcn * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * Visual Studio V2017 * .NET Framework 4.5.2 * * 版本历史: * V1.0 2017年10月16日 * 基于gRPC构建的人证比对服务器端实现 ------------------------------------------------------------ */ using Com.FirstSolver.FR; using Com.FirstSolver.Splash; using Grpc.Core; using System; using System.Collections.Generic; using System.ComponentModel; using System.Management; using System.Net; using System.Text.RegularExpressions; using System.Threading; using System.Windows; namespace Splash { public partial class FrServerWindow : Window, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// 线程同步锁 /// </summary> private object theLock = new object(); /// <summary> /// 服务访问数 /// </summary> private int InnerCountService = 0; public int CountService { get { return InnerCountService; } set { this.InnerCountService = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CountService")); } } } /// <summary> /// 图像处理数 /// </summary> private int InnerCountAll = 0; public int CountAll { get { return InnerCountAll; } set { this.InnerCountAll = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CountAll")); } } } /// <summary> /// 比对通过数 /// </summary> private int InnerCountPass = 0; public int CountPass { get { return InnerCountPass; } set { this.InnerCountPass = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CountPass")); } } } /// <summary> /// 比对失败数 /// </summary> private int InnerCountDeny = 0; public int CountDeny { get { return InnerCountDeny; } set { this.InnerCountDeny = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CountDeny")); } } } /// <summary> /// 比对异常数 /// </summary> private int InnerCountException; public int CountException { get { return InnerCountException; } set { this.InnerCountException = value; if (this.PropertyChanged != null) { this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("CountException")); } } } /// <summary> /// 服务器是否已运行 /// </summary> private bool IsServerRunning = false; /// <summary> /// 服务器停止事件 /// </summary> private ManualResetEvent ServerShutdownEvent = new ManualResetEvent(false); public FrServerWindow() { InitializeComponent(); ResetStatistics(); // 统计数据初始化 } private void Window_Loaded(object sender, RoutedEventArgs e) { // 列举本机所有的有效IP地址(自动过滤掉虚拟网卡IP地址) string[] IPCollection = GetLocalIPv4Address(); if (IPCollection != null) { comboBoxServerIP.ItemsSource = IPCollection; comboBoxServerIP.IsEnabled = !(IPCollection.Length == 1); // 如果本机只有一个有效IP地址,则直接锁定 comboBoxServerIP.SelectedIndex = 0; } } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (IsServerRunning) { buttonService.IsEnabled = false; ServerShutdownEvent.Set(); } } // 重置统计数据 private void ButtonReset_Click(object sender, RoutedEventArgs e) { ResetStatistics(); } // 开启或停止服务 private void ButtonService_Click(object sender, RoutedEventArgs e) { buttonService.IsEnabled = false; if (IsServerRunning) { ServerShutdownEvent.Set(); } else { try { IPAddress ServerIP = IPAddress.Parse(comboBoxServerIP.Text); int ServerPort = Convert.ToInt32(textBoxServerPort.Text); ThreadPool.QueueUserWorkItem(StartServiceServer, new GrpcServerAddress(ServerIP.ToString(), ServerPort)); } catch (Exception exception) { string ErrorMessage = exception.Message; if (string.IsNullOrEmpty(ErrorMessage)) ErrorMessage = exception.InnerException.Message; MessageBoxPlus.Show(this, ErrorMessage, "异常", MessageBoxButton.OK, MessageBoxImage.Error); } } } // 开启服务 private void StartServiceServer(object state) { GrpcServerAddress Address = state as GrpcServerAddress; try { ServerShutdownEvent.Reset(); using (FrServiceImpl theService = new FrServiceImpl()) { theService.OnFaceIdCompareEvent += FaceIdCompareEventHandler; Server server = new Server { Services = { FrService.BindService(theService) }, Ports = { new ServerPort(Address.Host, Address.Port, ServerCredentials.Insecure) } }; server.Start(); SetStatus(true); if (ServerShutdownEvent.WaitOne()) { server.ShutdownAsync().Wait(); } SetStatus(false); } } catch (Exception exception) { string ErrorMessage = exception.Message; if (string.IsNullOrEmpty(ErrorMessage)) ErrorMessage = exception.InnerException.Message; MessageBoxPlus.Show(this, ErrorMessage, "异常", MessageBoxButton.OK, MessageBoxImage.Error); } } public void SetStatus(bool isServerRunning) { this.Dispatcher.Invoke(new Action<bool>((status) => { if (status) { this.buttonService.Content = "停止服务"; } else { this.buttonService.Content = "开启服务"; } IsServerRunning = status; this.buttonService.IsEnabled = true; }), isServerRunning); } // 统计数据初始化 private void ResetStatistics() { CountService = 0; CountAll = 0; CountPass = 0; CountDeny = 0; CountException = 0; } public void FaceIdCompareEventHandler(object sender, FaceIdCompareEventArgs e) { lock (theLock) { CountService++; CountAll += e.CountAll; CountPass += e.CountPass; CountDeny += e.CountDeny; CountException += e.CountException; } } /// <summary> /// 获取本机IP地址列表 /// </summary> /// <param name="isIncludeUsb">是否包含USB网卡,默认为不包含</param> /// <returns>本机真实网卡信息</returns> public static string[] GetLocalIPv4Address(bool isIncludeUsb = false) { // IPv4正则表达式 const string IPv4RegularExpression = "^(?:(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))\\.){3}(?:25[0-5]|2[0-4]\\d|((1\\d{2})|([1-9]?\\d)))$"; // 注意:只获取已连接的网卡 string NetworkAdapterQueryString; if (isIncludeUsb) NetworkAdapterQueryString = "SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))"; else NetworkAdapterQueryString = "SELECT * FROM Win32_NetworkAdapter WHERE (NetConnectionStatus = 2) AND (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%')) AND (NOT (PNPDeviceID LIKE 'USB%'))"; ManagementObjectCollection NetworkAdapterQueryCollection = new ManagementObjectSearcher(NetworkAdapterQueryString).Get(); if (NetworkAdapterQueryCollection == null) return null; List<string> IPv4AddressList = new List<string>(NetworkAdapterQueryCollection.Count); foreach (ManagementObject mo in NetworkAdapterQueryCollection) { // 获取网卡配置信息 string ConfigurationQueryString = "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE Index = " + mo["Index"]; ManagementObjectCollection ConfigurationQueryCollection = new ManagementObjectSearcher(ConfigurationQueryString).Get(); if (ConfigurationQueryCollection == null) continue; foreach (ManagementObject nacmo in ConfigurationQueryCollection) { if ((bool)nacmo["IPEnabled"]) { if (nacmo["IPAddress"] is string[] IPCollection) { foreach (string adress in IPCollection) { Match match = Regex.Match(adress, IPv4RegularExpression); if (match.Success) { IPv4AddressList.Add(adress); break; } } } } } } if (IPv4AddressList.Count > 0) return IPv4AddressList.ToArray(); else return null; } } public class GrpcServerAddress { public readonly string Host; public readonly int Port; public GrpcServerAddress(string host, int port) { Host = host; Port = port; } } }