WPF真入门教程28--项目案例--MQTT服务器和客户端

news/2024/2/29 15:53:56/文章来源:https://blog.csdn.net/hqwest/article/details/135624942

1、先上图看帅照

这个案例还是布局加视图模型,样式应用,业务逻辑,该项目是一个mqtt服务器和客户端的通信工具,这里不去分析mqtt的通信原理,关注在于wpf技能的应用,能够掌握这个例子,离项目开发也差不多了,只是没有跟db打交道,本项目重点在于理解mvvm模式,开发环境依然是vs2022,.netframework 4.8,wpf应用程序。

 

默认启动的效果

 

最大化的效果,控件没有变形没有走样,说明wpf的技术还是不错的,界面没有变形,不象winform,控件会走样。

2、服务器这么搞

1、创建项目

 

2、添加包组件MQTTNET  

3、创建相关的目录及文件  

4、设置UI布局界面  

完全代码:

<Window x:Class="MQTTNETServerWPF.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:MQTTNETServerWPF.ViewModel"mc:Ignorable="d" Background="Transparent" WindowStartupLocation="CenterScreen"FontSize="13" FontFamily="Microsoft YaHei" FontWeight="ExtraLight" Foreground="#333"Title="MainWindow" Height="550" Width="890"><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"/></WindowChrome.WindowChrome><Window.DataContext><local:MainWindowViewModel/></Window.DataContext><Grid ShowGridLines="true"  ><Grid.RowDefinitions><RowDefinition Height="70"/><RowDefinition/></Grid.RowDefinitions><TextBlock Grid.Row="0" FontWeight="Bold" Background="BlanchedAlmond"  Text="WPF版MQTT服务器程序" FontSize="25" VerticalAlignment="Center" Margin="6,20,0,0" Foreground="#666"   /><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="220"/><ColumnDefinition/></Grid.ColumnDefinitions><Border BorderBrush="#EEE" BorderThickness="0,0,1,0"/><!--左侧布局--><StackPanel Grid.Column="0" Margin="20" ><TextBlock Text="主机地址"/><TextBox Text="{Binding Server.ServerIP}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"  /><TextBlock Text="端口号" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerPort}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"  /><TextBlock Text="连接账号" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerName}"  Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"    /><TextBlock Text="连接密码" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerPwd}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"  /><Button Content="启动服务" Margin="0,30,0,0" Height="30"  Command="{Binding StartCommand}" Style="{StaticResource ButtonStyle}" /><Button Content="停止服务" Margin="0,10" Height="30"  Command="{Binding StopCommand}"  Style="{StaticResource ButtonStyle}"/></StackPanel><!--右侧布局--><Grid Grid.Column="1"><Grid.RowDefinitions><RowDefinition Height="2*"/><RowDefinition Height="3*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><GridSplitter VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="4" Background="#F7F9FA" Grid.ColumnSpan="2" Margin="0,0,3,0"/><Grid Margin="20,20,10,15"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="在线Client列表"/><ListBox Grid.Row="1"   ItemsSource="{Binding ClientsList}"/></Grid><Grid Margin="10,20,20,15" Grid.Column="1"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="Topic主题列表"/><ListView Grid.Row="1"   ItemsSource="{Binding TopicsList}"></ListView></Grid><Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="20,10,20,20"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="消息"/><TextBox  Grid.Row="1"   x:Name="txtRich" ToolTip="右键清理内容" Text="{Binding ConnectWords}" Height="200" Background="White" VerticalContentAlignment="Top" Padding="3,0" Margin="10,9,10,10"    ><!--添加一个右键菜单的功能,即清空--><TextBox.ContextMenu><ContextMenu><MenuItem x:Name="menuClear" Click="miClear_Click"  Header="清空内容"></MenuItem></ContextMenu></TextBox.ContextMenu></TextBox></Grid></Grid></Grid></Grid>
</Window>

 5、视图模型,属性绑定和命令绑定

using MQTTnet.Client.Receiving;
using MQTTnet;
using MQTTnet.Server;
using MQTTNETServerWPF.Command;
using MQTTNETServerWPF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Collections.ObjectModel;
using MQTTnet.Certificates;
using MQTTnet.Protocol;
using System.Runtime.Remoting.Messaging;namespace MQTTNETServerWPF.ViewModel
{public class MainWindowViewModel : ViewModelBase{private IMqttServer mqttserver;//mqtt服务器List<TopicItem> Topics = new List<TopicItem>();public MainWindowViewModel(){//创建服务器对象mqttserver = new MqttFactory().CreateMqttServer();mqttserver.ApplicationMessageReceivedHandler =new MqttApplicationMessageReceivedHandlerDelegate(new Action<MqttApplicationMessageReceivedEventArgs>(Server_ApplicationMessageReceived));//绑定消息接收事件mqttserver.ClientConnectedHandler =new MqttServerClientConnectedHandlerDelegate(new Action<MqttServerClientConnectedEventArgs>(Server_ClientConnected));//绑定客户端连接事件mqttserver.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(new Action<MqttServerClientDisconnectedEventArgs>(Server_ClientDisconnected));//绑定客户端断开事件mqttserver.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(new Action<MqttServerClientSubscribedTopicEventArgs>(Server_ClientSubscribedTopic));//绑定客户端订阅主题事件mqttserver.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(new Action<MqttServerClientUnsubscribedTopicEventArgs>(Server_ClientUnsubscribedTopic));//绑定客户端退订主题事件mqttserver.StartedHandler = new MqttServerStartedHandlerDelegate(new Action<EventArgs>(Server_Started));//绑定服务端启动事件mqttserver.StoppedHandler = new MqttServerStoppedHandlerDelegate(new Action<EventArgs>(Server_Stopped));//绑定服务端停止事件}#region 方法/// 绑定消息接收事件/// </summary>/// <param name="e"></param>private void Server_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e){string msg = e.ApplicationMessage.ConvertPayloadToString();WriteLog(">>> 收到消息:" + msg + ",QoS =" + e.ApplicationMessage.QualityOfServiceLevel + ",客户端=" + e.ClientId + ",主题:" + e.ApplicationMessage.Topic);}/// <summary>/// 绑定客户端连接事件/// </summary>/// <param name="e"></param>private void Server_ClientConnected(MqttServerClientConnectedEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{this.ClientsList.Add(e.ClientId);});WriteLog(">>> 客户端" + e.ClientId + "连接");});}/// <summary>/// 绑定客户端断开事件/// </summary>/// <param name="e"></param>private void Server_ClientDisconnected(MqttServerClientDisconnectedEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{this.ClientsList.Remove(e.ClientId);});WriteLog(">>> 客户端" + e.ClientId + "断开");});}/// <summary>/// 绑定客户端订阅主题事件/// </summary>/// <param name="e"></param>private void Server_ClientSubscribedTopic(MqttServerClientSubscribedTopicEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{var topic = Topics.FirstOrDefault(t => t.Topic == e.TopicFilter.Topic);if (topic == null){topic = new TopicItem { Topic = e.TopicFilter.Topic, Count = 0 };Topics.Add(topic);}if (!topic.Clients.Exists(c => c == e.ClientId)){topic.Clients.Add(e.ClientId);topic.Count++;}this.TopicsList.Clear();foreach (var item in this.Topics){this.TopicsList.Add($"{item.Topic}:{item.Count}");}});WriteLog(">>> 客户端" + e.ClientId + "订阅主题" + e.TopicFilter.Topic);});}/// <summary>/// 绑定客户端退订主题事件/// </summary>/// <param name="e"></param>private void Server_ClientUnsubscribedTopic(MqttServerClientUnsubscribedTopicEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{var topic = Topics.FirstOrDefault(t => t.Topic == e.TopicFilter);if (topic != null){topic.Count--;topic.Clients.Remove(e.ClientId);}this.TopicsList.Clear();foreach (var item in this.Topics){this.TopicsList.Add($"{item.Topic}:{item.Count}");}});WriteLog(">>> 客户端" + e.ClientId + "退订主题" + e.TopicFilter);});}/// <summary>/// 绑定服务端启动事件/// </summary>/// <param name="e"></param>private void Server_Started(EventArgs e){WriteLog(">>> 服务端已启动!");}/// <summary>/// 绑定服务端停止事件/// </summary>/// <param name="e"></param>private void Server_Stopped(EventArgs e){WriteLog(">>> 服务端已停止!");}/// <summary>/// 显示日志/// </summary>/// <param name="message"></param>public void WriteLog(string message){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{ConnectWords = message + "\r";});});}#endregion#region 属性private MqttServerModel server = new MqttServerModel("127.0.0.1", "1869", "boss", "1234");//服务器实体/// <summary>/// 当前服务器对象/// </summary>public MqttServerModel Server{get { return server; }set{server = value;OnPropertyChanged();}}private string connectWords = "";/// <summary>/// 连接状态/// </summary>public string ConnectWords{get { return connectWords; }set{connectWords = value;OnPropertyChanged();}}private ObservableCollection<string> clientsList = new ObservableCollection<string>();/// <summary>/// 客户列表/// </summary>public ObservableCollection<string> ClientsList{get { return clientsList; }set{clientsList = value;OnPropertyChanged();}}private ObservableCollection<string> topicsList = new ObservableCollection<string>();/// <summary>/// 主题列表/// </summary>public ObservableCollection<string> TopicsList{get { return topicsList; }set{topicsList = value;OnPropertyChanged();}}#endregion#region 命令/// <summary>/// 启动命令/// </summary>[Obsolete]public ICommand StartCommand{get{return new RelayCommand(async o =>{var optionBuilder = new MqttServerOptionsBuilder().WithDefaultEndpointBoundIPAddress(System.Net.IPAddress.Parse(Server.ServerIP)).WithDefaultEndpointPort(int.Parse(Server.ServerPort)).WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(5000)).WithConnectionValidator(t =>{string un = "", pwd = "";un = Server.ServerName;pwd = Server.ServerPwd;if (t.Username != un || t.Password != pwd){t.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;}else{t.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;}});var option = optionBuilder.Build();//启动await mqttserver.StartAsync(option);});}}/// <summary>/// 启动命令/// </summary>[Obsolete]public ICommand StopCommand{get{return new RelayCommand(async o =>{ if (server != null){await mqttserver.StopAsync();} });}}#endregion}
}
1)属性绑定

2)视图绑定

 

 3)命令绑定

4)样式应用

 

 6、启动看效果

3、客户端跟着搞

1、添加项目MQTTNETClientWPF

2、添加客户端的组件

3、创建相关的类文件及目录  

4、设计UI布局 

完整代码 :

<Window x:Class="MQTTNETClientWPF.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:MQTTNETClientWPF.ViewModel"mc:Ignorable="d" Background="Transparent" WindowStartupLocation="CenterScreen"FontSize="13" FontFamily="Microsoft YaHei" FontWeight="ExtraLight" Foreground="#333"Title="MainWindow" Height="600" Width="850"><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"/></WindowChrome.WindowChrome><Window.DataContext><local:MainWindowViewModel/></Window.DataContext><Grid  ShowGridLines="true" ><Grid.RowDefinitions><RowDefinition Height="70"/><RowDefinition/></Grid.RowDefinitions><TextBlock Grid.Row="0" FontWeight="Bold"  Text="WPF版MQTT客户端程序" FontSize="25" VerticalAlignment="Center" Margin="6,20,0,0" Foreground="#666" Background="BlanchedAlmond"  /><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="220"/><ColumnDefinition/></Grid.ColumnDefinitions><Border BorderBrush="#EEE" BorderThickness="0,0,1,0"/><StackPanel Margin="20"><TextBlock Text="主机地址"/><TextBox Text="{Binding Client.ServerIP}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbHostAddr"/><TextBlock Text="端口号" Margin="0,5,0,0"/><TextBox  Text="{Binding Client.ServerPort}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"   Name="tbHostPort"/><TextBlock Text="连接账号" Margin="0,5,0,0"/><TextBox  Text="{Binding Client.ServerName}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbUsername"/><TextBlock Text="连接密码" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ServerPwd}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"  Name="tbPassword"/><TextBlock Text="客户端ID" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ClientId}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10"   Name="tbClientId"/><Button Content="连接" Margin="0,30,0,0" Height="30" Command="{Binding OpenCommand}"  Style="{StaticResource ButtonStyle}"/><Button Content="断开" Margin="0,10" Height="30"  Command="{Binding CloseCommand}" Style="{StaticResource ButtonStyle}"/></StackPanel><Grid Grid.Column="1" Margin="20,10"><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="auto"/><RowDefinition/></Grid.RowDefinitions><Grid><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition Height="50"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="订阅" VerticalAlignment="Center" Margin="5,0"/><TextBlock Text="主题" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Topic}" Grid.Row="1" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1"  Name="tbTopic"/><Button Width="50" Grid.Row="1" Height="30" Content="订阅" Grid.Column="2" Margin="5,10,0,10"   Command="{Binding SubscriteCommand}"  Style="{StaticResource ButtonStyle}"  HorizontalAlignment="Left"/></Grid><Grid Grid.Row="1" Margin="0,20"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition Height="50"/><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="发布" VerticalAlignment="Center" Margin="5,0"/><TextBlock Text="主题" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Topic}" Grid.Row="1" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1"   Name="tbPubTopic"/><TextBlock Text="内容" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Pubmsg}"  Grid.Row="2" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1"  Name="tbContent"/><Button Width="50" Grid.Row="2" Height="30"  Content="发布" Grid.Column="2" Margin="5,0,5,0"  Command="{Binding PublishCommand}"  Style="{StaticResource ButtonStyle}"  VerticalAlignment="Top"/></Grid><Grid Grid.Row="2" Margin="0,10,0,0"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="消息" VerticalAlignment="Center" Margin="5,0"/><TextBox  Grid.Row="1"  x:Name="txtRich" ToolTip="右键清理内容" Text="{Binding ConnectWords}" Height="200"  Background="White" VerticalContentAlignment="Top"  Padding="3,0" Margin="10,9,75,10"  ><!--添加一个右键菜单的功能,即清空--><TextBox.ContextMenu><ContextMenu><MenuItem x:Name="menuClear" Click="miClear_Click"  Header="清空内容"></MenuItem></ContextMenu></TextBox.ContextMenu></TextBox></Grid></Grid></Grid></Grid>
</Window>

 5、视图模型viewmodel

using MQTTnet.Client.Options;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTNETClientWPF.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using MQTTNETClientWPF.Model;
using MQTTnet;namespace MQTTNETClientWPF.ViewModel
{public class MainWindowViewModel : ViewModelBase{private IManagedMqttClient mqttClient; //mqtt客户端public MainWindowViewModel(){var factory = new MqttFactory();mqttClient = factory.CreateManagedMqttClient();//创建客户端对象//绑定断开事件mqttClient.UseDisconnectedHandler(async ee =>{WriteLog(DateTime.Now.ToString() + "与服务器之间的连接断开了,正在尝试重新连接");// 等待 5s 时间await Task.Delay(TimeSpan.FromSeconds(5));try{mqttClient.UseConnectedHandler(cc =>{WriteLog(">>> 连接到服务成功!");});}catch (Exception ex){Console.WriteLine($"重新连接服务器失败:{ex}");}});//绑定接收事件mqttClient.UseApplicationMessageReceivedHandler(aa =>{try{string msg = aa.ApplicationMessage.ConvertPayloadToString();WriteLog(">>> 消息:" + msg + ",QoS =" + aa.ApplicationMessage.QualityOfServiceLevel + ",客户端=" + aa.ClientId + ",主题:" + aa.ApplicationMessage.Topic);}catch (Exception ex){WriteLog($"+ 消息 = " + ex.Message);} });//绑定连接事件mqttClient.UseConnectedHandler(ee =>{WriteLog(">>> 连接到服务器成功");});}/// <summary>/// 显示日志/// </summary>/// <param name="message"></param> public void WriteLog(string message){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{ConnectWords = message + "\r";});});}#region 属性private MqttClientModel client = new MqttClientModel("127.0.0.1", "1869", "boss", "1234", "c1");//服务器实体/// <summary>/// 连接对象/// </summary>public MqttClientModel Client{get { return client; }set{client = value;OnPropertyChanged();}}private string connectWords = "";/// <summary>/// 连接状态/// </summary>public string ConnectWords{get { return connectWords; }set{connectWords = value;OnPropertyChanged();}}private string topic = "shanghai";/// <summary>/// 主题/// </summary>public string Topic{get { return topic; }set{topic = value;OnPropertyChanged();}}private string pubmsg = "0103";/// <summary>/// 发布/// </summary>public string Pubmsg{get { return pubmsg; }set{pubmsg = value;OnPropertyChanged();}}#endregion#region 命令/// <summary>/// 连接命令/// </summary> public ICommand OpenCommand{get{return new RelayCommand(async o =>{var mqttClientOptions = new MqttClientOptionsBuilder().WithClientId(this.Client.ClientId).WithTcpServer(this.Client.ServerIP, int.Parse(this.Client.ServerPort)).WithCredentials(this.Client.ServerName, this.Client.ServerPwd);var options = new ManagedMqttClientOptionsBuilder().WithAutoReconnectDelay(TimeSpan.FromSeconds(5)).WithClientOptions(mqttClientOptions.Build()).Build();//开启var t = mqttClientOptions;await mqttClient.StartAsync(options);});}}/// <summary>/// 断开命令/// </summary> public ICommand CloseCommand{get{return new RelayCommand(async o =>{if (mqttClient != null){if (mqttClient.IsStarted){await mqttClient.StopAsync();}mqttClient.Dispose();}});}}/// <summary>/// 订阅命令/// </summary> [Obsolete]public ICommand SubscriteCommand{get{return new RelayCommand(async o =>{if (string.IsNullOrWhiteSpace(this.Topic)){WriteLog(">>> 请输入主题");return;}//在 MQTT 中有三种 QoS 级别: //At most once(0) 最多一次//At least once(1) 至少一次//Exactly once(2) 恰好一次//await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(this.tbTopic.Text).WithAtMostOnceQoS().Build());//最多一次, QoS 级别0await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(this.Topic).WithAtLeastOnceQoS().Build());//恰好一次, QoS 级别1 WriteLog($">>> 成功订阅 {this.Topic}");});}}/// <summary>/// 发布命令/// </summary> public ICommand PublishCommand{get{return new RelayCommand(async o =>{if (string.IsNullOrWhiteSpace(this.Topic)){WriteLog(">>> 请输入主题");return;}var result = await mqttClient.PublishAsync(this.Topic,this.Pubmsg,MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);//恰好一次, QoS 级别1 WriteLog($">>> 主题:{this.Topic},消息:{this.Pubmsg},结果: {result.ReasonCode}");});}}#endregion}
}
1)属性绑定
2)视图绑定
3)命令绑定
4)样式应用

6、启动客户端

4、测试效果

 

 最大化效果

5、完整代码打包

链接:https://pan.baidu.com/s/1sfQnGEEcsRTBKUSDOdCeTA 
提取码:z2hj 
--来自百度网盘超级会员V9的分享

 分享不易,讲解不易,思路不易,原创不易,整理不易,伙伴们动动你的金手指,你的支持是我最大的动力。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_926000.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#编程-在线程中使用同步

在线程中使用同步 在线程应用程序中,线程需要相互共享数据。但是,应用程序应该确保一个线程不更改另一个线程使用的数据。考虑有两个线程的场景。一个线程从文件读取工资,另一个线程尝试更新工资。当两个线程同时工作时,数据就会受损。下图显示了两个线程同时访问一个文件…

杨中科 .NETCORE EFCORE第七部分 一对一,多对多

一对一 一对一关系配置 1、builder.HasOne(o >o.Delivery).WithOne(d>d.Order).HasForeignKey(d>dOrderId); 2、测试插入和获取数据 示例 新建 Order 新建 Delivery DeliveryConfig OrderConfig 执行 迁移命令 查看数据库 测试数据插入 运行查看数据 多对多…

Python文件自动化处理

os模块 Python标准库和操作系统有关的操作创建、移动、复制文件和文件夹文件路径和名称处理 路径的操作 获取当前Python程序运行路径不同操作系统之间路径的表示方式 windows中采用反斜杠(\)作为文件夹之间的分隔符 Mac和Linux中采用斜杠(/)作为文件夹之间的分隔符 把文件…

Qt优秀开源项目之二十一:遇见QSkinny,一个轻量级Qt UI库

目录 一.QSkinny简介 二.工作原理 三.编译 一.QSkinny简介 QSkinny库基于Qt Graphic View和Qt/Quick中少量的核心类。它提供了一组轻量级控件&#xff0c;可以在C或QML中使用这些控件。QSkinny默认是启用硬件加速的&#xff0c;非常适合嵌入式设备&#xff0c;目前已经应用于…

[DL]深度学习_Feature Pyramid Network

FPN结构详解 目录 一、概念介绍 二、结构详解 1、对比试验 2、特征图融合 3、结构详解 4、不同尺度预测 5、Proposal映射到预测特征层 一、概念介绍 Feature Pyramid Network (FPN)是一种用于目标检测和语义分割的神经网络架构。它的目标是解决在处理不同尺度的图像时…

SQLServer 为角色开视图SELECT权限,报错提示需要开基础表权限

问题&#xff1a; 创建了个视图V&#xff0c;里面包含V库的a表&#xff0c;和T库的b表 为角色开启视图V的SELECT权限&#xff0c;提示T库的b表无SELECT权限&#xff0c;报错如下 解决方案&#xff1a; ①在T库建个视图TV&#xff0c;里面包含b表&#xff08;注意是在b表的对…

基于SSM的戏剧推广网站的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue、HTML 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是…

使用串口 DMA 模式接收不定长数据

一、简介 曾经遇到客户有一个需求&#xff0c;需要用串口 DMA 的方式接收不定长度的数据&#xff0c;DMA 有个缺点就是在每次传输前需要设定好传输的字节长度&#xff0c;这种方式显然对于接收不定长度的数据来说没有那么灵活。但 DMA 也有着显著的优点&#xff0c;如可直接访…

Linux环境搭建FastDFS文件服务器(附带Nginx安装)

本文主要介绍在linux服务器如何搭建FastDFS文件服务器。大概分为9个步骤&#xff0c;由于内容较为繁琐。下面带你入坑&#xff01; 首先简单介绍一下FastDFS是淘宝资深架构师余庆老师主导开源的一个分布式文件系统&#xff0c;用C语言编写。适应与中小企业&#xff0c;对文件不…

电脑安装 Python提示“api-ms-win-crt-process-l1-1-0.dll文件丢失,程序无法启动”,快速修复方法,完美解决

在windows 10系统安装完python后&#xff0c;启动的时候&#xff0c;Windows会弹出错误提示框“无法启动此程序&#xff0c;因为计算机中丢失了api-ms-win-crt-process-l1-1-0.dll&#xff0c;尝试重新安装该程序以解决此问题。” api-ms-win-crt-process-l1-1-0.dll是一个动态…

网络层协议及IP编址与IP路由基础华为ICT网络赛道

目录 4.网络层协议及IP编址 4.1.网络层协议 4.2.IPv4地址介绍 4.3.子网划分 4.4.ICMP协议 4.5.IPv4地址配置及基本应用 5.IP路由基础 5.1.路由概述 5.2.静态路由 5.3.动态路由 5.4.路由高阶特性 4.网络层协议及IP编址 4.1.网络层协议 IPv4(Internet Protocol Versi…

C语言——编译和链接

&#xff08;图片由AI生成&#xff09; 0.前言 C语言是最受欢迎的编程语言之一&#xff0c;以其接近硬件的能力和高效性而闻名。理解C语言的编译和链接过程对于深入了解其运行原理至关重要。本文将详细介绍C语言的翻译环境和运行环境&#xff0c;重点关注编译和链接的各个阶段…

基于JavaWeb+BS架构+SpringBoot+Vue+Hadoop短视频流量数据分析与可视化系统的设计和实现

基于JavaWebBS架构SpringBootVueHadoop短视频流量数据分析与可视化系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 目  录 目  录 I 1绪 论 1 1.1开发背景 1 1.2开…

【国内访问github不稳定】可以尝试fastgithub解决这个问题

1、下载 https://github.com/dotnetcore/FastGithub https://github.com/dotnetcore/FastGithub/releases 官网下载即可&#xff0c;比如&#xff0c;我用的是这个&#xff1a;fastgithub_osx-x64.zip&#xff08;点这里下载&#xff09; 2、安装 如下图双击启动即可 3、…

大模型开启应用时代 数钉科技一锤定音

叮叮叮叮&#xff01;数钉智造大模型&#xff0c;“定音”强势发布&#xff01; 随着科技的飞速发展&#xff0c;大模型技术已逐渐成为推动产业变革的核心力量。在这一浪潮中&#xff0c;数钉科技凭借深厚的技术积累和敏锐的市场洞察力&#xff0c;成功利用大模型技术搭建起智能…

SSL之mkcert构建本地自签名

文章目录 1. 什么是SSL2. mkcert&#xff1a;快速生成自签名证书2.1 mkcert的工作流程如下&#xff1a;2.2 window 本地实现自签证书2.2.1 下载安装2.2.2 下载,生成本地 SSL2.2.3 生成 pem 自签证书,可供局域网内使用其他主机访问。2.2.4 使用-psck12 生成*.p12 文件 2.3 Sprin…

盲盒小程序搭建:为盲盒企业、创业者提供新的机遇

近年来&#xff0c;盲盒因其不确定性以及拆盲盒带来的惊喜感&#xff0c;受到了广大消费者的追捧&#xff01;盲盒是由各类手办等组成的&#xff0c;玩家能够以低价格拆到性价比高的盲盒商品&#xff0c;这种购物体验激发了玩家的购物乐趣&#xff0c;因此&#xff0c;盲盒行业…

植物大战僵尸-C语言搭建童年游戏(easyx)

游戏索引 游戏名称&#xff1a;植物大战僵尸 游戏介绍&#xff1a; 本游戏是在B站博主<程序员Rock>的视频指导下完成 想学的更详细的小伙伴可以移步到<程序员Rock>视频 语言项目&#xff1a;完整版植物大战僵尸&#xff01;可能是B站最好的植物大战僵尸教程了&…

文心一言 vs. ChatGPT:哪个更胜一筹?

文心一言 vs. ChatGPT&#xff1a;从简洁美到深度思考的文本生成之旅 近年来&#xff0c;文本生成工具的崛起使得人们在表达和沟通方面拥有了更多的选择。在这个领域中&#xff0c;文心一言和ChatGPT作为两个备受瞩目的工具&#xff0c;各自以独特的优势展现在用户面前。本文将…

第九讲 单片机驱动彩色液晶屏 控制RA8889软件:显存操作

单片机驱动TFT彩色液晶屏系列讲座 目录 第一讲 单片机最小系统STM32F103C6T6通过RA8889驱动彩色液晶屏播放视频 第二讲 单片机最小系统STM32F103C6T6控制RA8889驱动彩色液晶屏硬件框架 第三讲 单片机驱动彩色液晶屏 控制RA8889软件:如何初始化 第四讲 单片机驱动彩色液晶屏 控…