当前位置: 首页 > news >正文

C#实现本地服务器客户端私聊通信

(一)需求

       在游戏中我们经常能够看到玩家与玩家之间可以进行私聊,在QQ或微信中最基本的功能就是用户与用户之间的通信。抽象成计算机网络,就是两个客户端通过服务器进行私聊通信,两个客户端可以互相看到对方发送过来的信息。这种两个客户端的私聊通信是如何实现的呢?在本篇文章我们就来探讨一下。

(二)解决思路

       这个需求的重点部分在于网络通信,需要我们掌握基本的计算机网络通信知识,具体到每种编程语言又有对应的API。如果把这个需求抽象到计算机网络中,我们就可以理解成两个客户端向服务器发送信息,服务器接收信息后又把信息发送给另一个客户端。这样,一个客户端就可以接收到另一个客户端发送的信息了。

(三)设计思路

       服务器基于本地服务器开发,通过一个单独的C#控制台项目模拟,编程语言使用C#,客户端通过Unity3D构建GUI并编写客户端脚本。两个客户端则通过打开两个Unity3D项目的可执行文件进行模拟,客户端的GUI需要有调试面板、客户端名称下拉菜单、连接和断开连接按钮、消息显示面板、消息输入框和消息发送按钮等。

(四)代码实现

        由于代码中引用了自定义的网络通信共享库NetShare,关于NetShare请阅读这篇文章。


       客户端

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;
using UnityEngine.UI;
/*
自定义网络通信共享库NetShare,包括通用数据包DataPacket、私聊频道服务器数据包PSDataPacket、
服务器数据包ServerDataPacket和私聊频道客户端数据包PCDataPacket等。
*/
using NetShare;
using System.Threading;
using System.Linq;//私聊频道客户端
public class PersonalChannelClient : MonoBehaviour
{public Text BaseInfo;//显示Socket连接基本信息的文本public Text EchoContents;//Socket回显信息的文本public Text ChatContents;//聊天信息的文本public Dropdown Friends;//目标客户端名称下拉菜单public Dropdown ClientMenu;//客户端名称下拉菜单public Button Connect;//连接按钮public Button DisConnect;//断开连接按钮public InputField SendInput;//聊天消息输入框public Button Send;//聊天信息发送按钮static string ipAddressStr;//IP地址字符串static int port;//端口static IPAddress iPAddress;//IP地址对象static IPEndPoint iPEndPoint;//IP端点对象string clientName, sendStr;//客户端名称和发送信息字符串Socket currentClientSocket;//当前客户端Socketbool isLockSend;//是否锁定聊天信息发送按钮byte[] buffer;//消息接收缓冲区Queue<string> echoContentQueue, chatContentQueue;//回显信息队列和聊天信息队列PCDataPacket dataPacket;//通用数据包List<string> desClientNames;//目标客户端名称合集//反映Socket是否与服务器有效连接的属性bool isConnected{get{if (currentClientSocket == null) return false;return !currentClientSocket.Poll(10, SelectMode.SelectRead) && currentClientSocket.Connected;}}void Start(){//初始化ipAddressStr = "127.0.0.1";clientName = ClientMenu.options.Count > 0 ? ClientMenu.options[0].text : "";port = 5500;iPAddress = IPAddress.Parse(ipAddressStr);iPEndPoint = new IPEndPoint(iPAddress, port);buffer = new byte[1024];echoContentQueue = new Queue<string>();chatContentQueue = new Queue<string>();desClientNames = new List<string>() { "None" };//为UI控件添加监听事件ClientMenu.onValueChanged.AddListener((index) =>{clientName = ClientMenu.options[index].text;});Connect.onClick.AddListener(() =>{Thread thread = new Thread(new ThreadStart(ConnectDeal));thread.Start();});DisConnect.onClick.AddListener(() =>{Thread thread = new Thread(new ThreadStart(DisConnectDeal));thread.Start();});Send.onClick.AddListener(() =>{sendStr = SendInput.text;Thread thread = new Thread(new ThreadStart(SendDeal));thread.Start();SendInput.text = string.Empty;});}void Update(){//不断更新Socket基本信息BaseInfo.text = $"ClientName:{clientName}" +string.Format("\nSocketHashCode:{0}", currentClientSocket == null ? "None" : currentClientSocket.GetHashCode().ToString()) +$"\nisLock:{isLockSend}" +string.Format("\nPoll:{0}", currentClientSocket == null ? "None" : (!currentClientSocket.Poll(10, SelectMode.SelectRead)).ToString()) +string.Format("\nIsConnected:{0}", currentClientSocket == null ? "False" : currentClientSocket.Connected.ToString());//更新回显信息if (echoContentQueue.Count > 0){while (echoContentQueue.Count > 0){SetEchoContents(echoContentQueue.Dequeue());}}//更新聊天信息if (chatContentQueue.Count > 0){while (chatContentQueue.Count > 0){SetChatContents(chatContentQueue.Dequeue());}}//更新目标客户端名称下拉菜单if (desClientNames?.Count > 0){Friends.AddOptions(desClientNames);desClientNames.Clear();}}//设置回显信息相关UI的内容void SetEchoContents(string text){EchoContents.text += text;}//设置聊天信息相关UI的内容void SetChatContents(string text){ChatContents.text += text;}//执行逻辑:Socket异步连接处理void ConnectDeal(){echoContentQueue.Enqueue($"\n客户端{clientName}正在请求服务器连接...");Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);clientSocket.BeginConnect(iPEndPoint, ConnectCallback, clientSocket);}//执行逻辑:Socket异步断开连接处理void DisConnectDeal(){echoContentQueue.Enqueue($"\n客户端{clientName}正在断开与服务器的连接...");if (isConnected){currentClientSocket.Shutdown(SocketShutdown.Both);currentClientSocket.BeginDisconnect(false, DisConnectCallback, currentClientSocket);}else echoContentQueue.Enqueue($"\n客户端{clientName}未与服务器建立连接,无法进行断开连接的操作...");}//执行逻辑:Socket异步接收信息处理void ReceiveDeal(){echoContentQueue.Enqueue($"\n客户端{clientName}开始监听服务器响应...");currentClientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, currentClientSocket);}//执行逻辑:Socket异步发送信息处理void SendDeal(){if (!isLockSend && !string.IsNullOrEmpty(sendStr)){dataPacket.mContent = sendStr;string v_desClientName = Friends.options[Friends.value].text;if (!v_desClientName.Equals("None")) dataPacket.mDestinationClientName = v_desClientName;byte[] bytes = dataPacket.ToBytes();currentClientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, currentClientSocket);}}//执行逻辑:Socket异步连接处理回调void ConnectCallback(IAsyncResult ar){try{Socket socket = ar.AsyncState as Socket;socket.EndConnect(ar);currentClientSocket = socket;if (isConnected){dataPacket = new PCDataPacket(){mLocalEndPointStr = socket.LocalEndPoint.ToString(),mClientName = clientName,mDestinationClientName = string.Empty,mContent = $"成功与服务器建立连接!"};byte[] bytes = dataPacket.ToBytes();socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, currentClientSocket);isLockSend = false;echoContentQueue.Enqueue($"\n<color=orange>客户端{clientName}与服务器连接成功!</color>");ReceiveDeal();}else echoContentQueue.Enqueue($"\n<color=red>客户端{clientName}与服务器连接失败!</color>");}catch (SocketException se){echoContentQueue.Enqueue($"\n<color=red>客户端{clientName}与服务器连接失败!</color>\n错误信息:{se.Message}");}}//执行逻辑:Socket异步断开连接处理回调void DisConnectCallback(IAsyncResult ar){try{isLockSend = true;Socket socket = ar.AsyncState as Socket;socket.EndDisconnect(ar);dataPacket = null;echoContentQueue.Enqueue($"\n<color=orange>客户端{clientName}与服务器断开连接操作成功!</color>");}catch (SocketException se){echoContentQueue.Enqueue($"\n客户端{clientName}与服务器断开连接操作失败!\n错误信息:{se.Message}");}}//执行逻辑:Socket异步发送信息处理回调void SendCallback(IAsyncResult ar){try{Socket socket = ar.AsyncState as Socket;socket.EndSend(ar);echoContentQueue.Enqueue($"\n客户端{clientName}向服务器发送了一条消息!");}catch (SocketException se){echoContentQueue.Enqueue($"\n客户端{clientName}向服务器发送信息操作失败!\n错误信息:{se.Message}");}}//执行逻辑:Socket异步接收信息处理回调void ReceiveCallback(IAsyncResult ar){try{Socket socket = ar.AsyncState as Socket;int count = socket.EndReceive(ar);DataPacket dataPacket = DataPacket.ToObject<DataPacket>(buffer.Take(count).ToArray());if (dataPacket is PSDataPacket psdp && psdp.mClientNames?.Length > 0){desClientNames.Clear();foreach (string name in psdp.mClientNames){if (Friends.options.FindIndex((od) => od.text.Equals(name)) == -1) desClientNames.Add(name);}}else if (dataPacket is ServerDataPacket sdp){string v_res = sdp.mContent;if (!string.IsNullOrEmpty(v_res)) chatContentQueue.Enqueue("\n" + v_res);}//若Socket连接有效则继续接收消息if (isConnected)socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, socket);}catch (SocketException se){echoContentQueue.Enqueue($"\n客户端{clientName}接收服务器消息失败!\n错误信息:{se.Message}");}}
}

        服务器

using System.Net.Sockets;
using System.Net;/*
自定义网络通信共享库NetShare,其中包括了私聊频道服务器数据包PSDataPacket、通用数据包DataPacket、
服务器数据包ServerDataPacket和私聊频道客户端数据包PCDataPacket等。*/using NetShare;namespace UnityServer
{//私聊频道服务器internal class PersonalChannelServer{private static string ipAddress = "127.0.0.1";//IP地址字符串private static int port = 5500;//端口private static int maxConnect = 20;//最大连接数private static byte[] buffer = new byte[1024];//消息缓冲区//客户端Socket合集,key为IPEndPoint字符串,value为服务器为客户端分配的Socketprivate static Dictionary<string, Socket> clients = new Dictionary<string, Socket>();private static Socket? serverSocket;//服务器Socket//客户端键值对,key为客户端名称,value为IPEndPoint字符串private static Dictionary<string, string> clientKVs = new Dictionary<string, string>();private static void Main(string[] args){Thread thread = new Thread(new ThreadStart(ServerDeal));thread.Start();Console.ReadLine();}//判断Socket是否进行有效连接private static bool IsConnected(Socket socket){if (socket == null) return false;return !socket.Poll(10, SelectMode.SelectRead) && socket.Connected;}//执行逻辑:服务器处理private static void ServerDeal(){serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);IPAddress v_ipAddress = IPAddress.Parse(ipAddress);serverSocket.Bind(new IPEndPoint(v_ipAddress, port));serverSocket.Listen(maxConnect);Console.WriteLine($"开启服务器[{serverSocket.LocalEndPoint}]...");serverSocket.BeginAccept(AcceptCallback, null);}//执行逻辑:Socket异步接收消息private static void ReceiveDeal(object? clientSocket){Console.WriteLine("********************");if (clientSocket == null) return;Socket? v_clientSocket = clientSocket as Socket;if (v_clientSocket == null) return;Console.WriteLine("接收到客户端的连接请求!");if (IsConnected(v_clientSocket))v_clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, v_clientSocket);}//添加客户端Socket到客户端Socket合集private static void AddClient(Socket clientSocket){if (clientSocket == null) return;EndPoint? endPoint = clientSocket.RemoteEndPoint;if (endPoint != null){string? v_endPointStr = endPoint.ToString();if (v_endPointStr != null) clients[v_endPointStr] = clientSocket;}}//向所有客户端发送指定信息private static void SendToAll(PSDataPacket dataPacket){if (dataPacket == null) return;byte[] bytes = dataPacket.ToBytes();foreach (Socket clientSocket in clients.Values){if (IsConnected(clientSocket)){Thread thread = new Thread(() =>{clientSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, clientSocket);});thread.Start();}}}//向指定的客户端发送服务器数据包private static void SendTo(ServerDataPacket dataPacket, Socket? destinationSocket){if (dataPacket == null || destinationSocket == null) return;byte[] bytes = dataPacket.ToBytes();if (IsConnected(destinationSocket)){Thread thread = new Thread(() =>{destinationSocket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, destinationSocket);});thread.Start();}}//Socket监听请求回调private static void AcceptCallback(IAsyncResult ar){try{if (serverSocket != null){Socket clientSocket = serverSocket.EndAccept(ar);AddClient(clientSocket);Thread thread = new Thread(new ParameterizedThreadStart(ReceiveDeal));thread.Start(clientSocket);serverSocket.BeginAccept(AcceptCallback, null);}}catch (SocketException se){Console.WriteLine("AcceptException:" + se.Message);}}//Socket发送信息回调private static void SendCallback(IAsyncResult ar){try{Socket? clientSocket = ar.AsyncState as Socket;if (clientSocket != null) clientSocket.EndSend(ar);}catch (SocketException se){Console.WriteLine("SendException:" + se.Message);}}//Socket接收信息回调private static void ReceiveCallback(IAsyncResult ar){try{Socket? clientSocket = ar.AsyncState as Socket;if (clientSocket != null){int bytesCount = clientSocket.EndReceive(ar);PCDataPacket? dataPacket = DataPacket.ToObject<PCDataPacket>(buffer.Take(bytesCount).ToArray());if (dataPacket != null){if (clientSocket.RemoteEndPoint != null){string? v_endPointStr = clientSocket.RemoteEndPoint.ToString();if (!string.IsNullOrEmpty(v_endPointStr)){clientKVs[dataPacket.mClientName] = v_endPointStr;SendToAll(new PSDataPacket(){mClientNames = clientKVs.Keys.ToArray()});}}string v_content = $"客户端{dataPacket.mClientName}:{dataPacket.mContent}";Socket? destinationSocket;string? endPointStr;clientKVs.TryGetValue(dataPacket.mDestinationClientName, out endPointStr);if (!string.IsNullOrEmpty(endPointStr) && clients.TryGetValue(endPointStr, out destinationSocket))SendTo(new ServerDataPacket() { mContent = v_content }, destinationSocket);}if (IsConnected(clientSocket))clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, clientSocket);}}catch (SocketException se){Console.WriteLine("ReceiveException:" + se.Message);}}}
}

(五)测试

       测试流程大概是先启动服务器,然后启动三个客户端,三个客户端分别以A、B、C的名称作为客户端名称与服务器建立连接,连接后再由客户端A、B、C分别向服务器发送信息,通过观察三个客户端的消息面板来确定测试结果,这里之所以启动三个客户端是为了进行对比测试,以区分多客户端的同频道通信,具体测试流程请观看下列视频:

本地服务器客户端单独通信

(六)总结

       在服务器端,我们通过一个C#控制台项目来模拟服务器后台,服务器与客户端具有类似的功能,同样具有发送、接收消息的功能,不同的是服务器具有监听客户端连接的功能,而客户端具有向服务器发送连接请求的功能,本质上这些都是通过Socket实现的功能,人为划分成服务器端和客户端。在客户端我们通过GUI将用户的操作进行可视化构建,实现了回显、客户端名称选择、连接、断开连接、发送和显示消息等基本交互。

       为了模拟多客户端并发操作,所有功能我们都采用了异步的方式启动,对于真正的网络通信而言,这对我们来说才刚刚开始,不过通过这个案例也让我们了解了基本的网络通信流程。

如果这篇文章对你有帮助,请给作者点个赞吧!

相关文章:

C#实现本地服务器客户端私聊通信

&#xff08;一&#xff09;需求 在游戏中我们经常能够看到玩家与玩家之间可以进行私聊&#xff0c;在QQ或微信中最基本的功能就是用户与用户之间的通信。抽象成计算机网络&#xff0c;就是两个客户端通过服务器进行私聊通信&#xff0c;两个客户端可以互相看到对方发送过来的信…...

PyTorch 之 Dataset 类入门学习

PyTorch 之 Dataset 类入门学习 Dataset 类简介 PyTorch 中的 Dataset 类是一个抽象类&#xff0c;用来表示数据集。通过继承 Dataset 类可以进行自定义数据集的格式、大小和其它属性&#xff0c;供后续使用&#xff1b; 可以看到官方封装好的数据集也是直接或间接的继承自 …...

Java update scheduler

引言 Java 更新调度器是 Java 中的一个特性&#xff0c;可以自动化 Java 应用程序的更新过程。它提供了一种方便的方式来安排 Java 应用程序的更新&#xff0c;确保其与最新的功能、错误修复和安全补丁保持同步。本文将深入介绍如何使用 Java 更新调度器&#xff0c;并解释它对…...

常见树种(贵州省):006栎类

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、麻栎 …...

拓扑排序-

有向无环图是拓扑排序 拓扑排序将图中所有的顶点排成一个线性序列&#xff0c;使得所有的有向边均从序列的前面指向后面。 拓扑排序使用深度优先搜索来实现&#xff0c;图中有环则无法进行拓扑排序 一个有向图&#xff0c;如果图中有入度为0的点&#xff0c;就把这个点删掉…...

Oracle数据库如何定位trace file位置

用一个示例来说明吧。 在导入master key时&#xff0c;出现错误&#xff1a; ADMINISTER KEY MANAGEMENTIMPORT KEYS WITH SECRET "my_secret"FROM /tmp/export.expIDENTIFIED BY keypwd5 WITH BACKUP; ADMINISTER KEY MANAGEMENT * ERROR at line 1: ORA-46655…...

电脑盘符错乱,C盘变成D盘怎么办?

在一些特殊情况下&#xff0c;磁盘盘符会出现错乱&#xff0c;C盘可能会变成D盘。那么&#xff0c;这该怎么办呢&#xff1f;下面我们就来了解一下。 通过磁盘管理更改盘符 磁盘管理是Windows自带的工具&#xff0c;它位于“计算机管理”的控制台中。管理硬盘及其所包含的卷或…...

Android WMS——客户端输入事件处理(十九)

前面的文章我们介绍了 WMS 中的输入服务的启动及事件处理,这一篇我们来看一下客户端对输入事件的处理。 一、事件初始化 事件的初始化就是在添加窗口的过程。 1、ViewRootImpl 源码位置:/frameworks/base/core/java/android/view/ViewRootImpl.java public void setView(…...

Python基础学习__测试报告

# 使用pycharm生成报告:只有在单独执行一个TestCase文件时可以生成,使用TestSuite等就不能用了 # 使用第三方的测试报告:例如:HTMLTestRunner第三方类库 #使用HTMLTestRunner这个执行对象# 1.获取第三方的测试运行类Runner模块(一个py文件),将其放在代码目录下 # 2.导包:unitte…...

bclinux aarch64 ceph 14.2.10 云主机 4节点 fio

ceph -s 由于是基于底层分布式存储的云主机&#xff0c;数据仅供参考 本地云盘性能 direct1 1M读取 IOPS134, BW134MiB/s [rootceph-client rbd]# cd / [rootceph-client /]# fio -filenamefio.bin -direct1 -iodepth 128 -thread -rwread -ioenginelibaio -bs1M -size10G -n…...

智能座舱架构与芯片- (14) 测试篇 上

一、 验证平台概要 1.1 测试软件方法论 “软件定义汽车” 的时代&#xff0c;软件在整车制造中的重要性日渐凸显。但不同于其他行业的软件开发&#xff0c;汽车行业有自己独特的软件开发要求。首先是需求严谨、需求层次复杂、需要通过专业的工具进行管理&#xff1b;其次开发…...

【Django-DRF用法】多年积累md笔记,第3篇:Django-DRF的序列化和反序列化详解

本文从分析现在流行的前后端分离Web应用模式说起&#xff0c;然后介绍如何设计REST API&#xff0c;通过使用Django来实现一个REST API为例&#xff0c;明确后端开发REST API要做的最核心工作&#xff0c;然后介绍Django REST framework能帮助我们简化开发REST API的工作。 全…...

Redis主从复制,哨兵和Cluster集群

主从复制&#xff1a; 主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff08;和同步&#xff09;&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。 缺陷&#xff1a;故障恢复无法自动化…...

Linux嵌入式I2C协议笔记

硬件&#xff1a; 1.I2C结构 在一个SOC中有一个或者多个I2C控制器&#xff0c;一个I2C控制器可以连接一个或多个I2C设备。 I2C总线需要两条线&#xff0c;时钟线SCL和数据线SDA 2.I2C传输数据格式 开始信号&#xff08;S&#xff09;&#xff1a;SCL为高电平时&#xff0c;S…...

科技的成就(五十三)

503、任天堂首次公开 Switch 2016 年 10 月 20 日&#xff0c;任天堂首次公开 Switch 正式名称及造型。Switch 是任天堂推出的混合型游戏机&#xff0c;可作为家用游戏机&#xff0c;也可作为便携式掌机。Switch 在开发过程中就以代号 NX 而闻名&#xff0c;成为当年的现象级产…...

Ubuntu22.04 编译 AOSP

在 Ubuntu 22.04 系统上搭建环境编译 AOSP(Android Open Source Project)需要进行以下步骤: 1, 更新系统:首先,确保您的 Ubuntu 22.04 系统已经更新到最新版本。可以使用以下命令进行系统更新: sudo apt update sudo apt upgrade2,安装必要的软件包:AOSP 编译需要一些…...

【计算机网络】多路复用的三种方案

文章目录 1. selectselect函数select的工作特性select的缺点 2. pollpoll函数poll与select的对比 3. epollepoll的三个接口epoll的工作原理epoll的优点LT和ET模式epoll的应用场景 &#x1f50e;Linux提供三种不同的多路转接&#xff08;又称多路复用&#xff09;的方案&#xf…...

供应链和物流的自动化新时代

今天&#xff0c;当大多数人想到物流自动化时&#xff0c;他们会想到设备。机器人、无人机和自主卡车运输在大家的谈话中占主导地位。全自动化仓库的视频在网上流传&#xff0c;新闻主播们为就业问题绞尽脑汁。这种炒作是不完整的&#xff0c;它错过了供应链和物流公司的机会。…...

Python与ArcGIS系列(九)自定义python地理处理工具

目录 0 简述1 创建自定义地理处理工具2 创建python工具箱0 简述 在arcgis中可以进行自定义工具箱,将脚本嵌入到自定义的可交互窗口工具中。本篇将介绍如何利用arcpy实现创建自定义地理处理工具以及创建python工具箱。 1 创建自定义地理处理工具 在arctoolbox中的自定义工具箱…...

Nginx部署前端项目

Nginx部署前端项目 1.在nginx官网http://nginx.org/en/download.html &#xff0c;下载稳定版本&#xff1a; 2.解压后&#xff0c;点击根目录中的nginx.exe即可启动Nginx&#xff0c;或是在nginx安装目录中启动cmd并输入以下命令启动&#xff1a; nginx.exe 或 start nginx3…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下&#xff0c;风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...