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

Socket编程详解(一)服务端与客户端的双向对话

目录

预备知识

视频教程

项目前准备知识点

1、服务器端程序的编写步骤

2、客户端程序编写步骤

代码部分 

      1、服务端FrmServer.cs文件

        2、客户端FrmClient.cs文件

        3、启动文件Program.cs

结果展示 


预备知识

请查阅博客http://t.csdnimg.cn/jE4Tp

视频教程

链接:https://pan.baidu.com/s/13fkwlppoP9aYcXHiFEbKGQ?pwd=cvzn 
提取码:cvzn

项目前准备知识点


1、服务器端程序的编写步骤

第一步:调用socket()函数创建一个用于通信的套接字。

第二步:给已经创建的套接字绑定一个端口号,这一般通过设置网络套接口地址和调用bind()函数来实现。
第三步:调用listen()函数使套接字成为一个监听套接字。
第四步:调用accept()函数来接受客户端的连接,这是就可以和客户端通信了。
第五步:处理客户端的连接请求

第六步:终止连接。

 



2、客户端程序编写步骤

第一步:调用socket()函数创建一个用于通信的套接字。

第二步:通过设置套接字地址结构,说明客户端与之通信的服务器的IP地址和端口号。
第三步:调用connect()函数来建立与服务器的连接。
第四步:调用读写函数发送或者接收数据。
第五步:终止连接。

 

代码部分 

      1、服务端FrmServer.cs文件

        FrmServer.cs窗体

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace SocketTCP
{//声明委托delegate void AddOnLineDelegate(string str, bool bl);//声明委托delegate void RecMsgDelegate(string str);public partial class FrmTCPServer : Form{public FrmTCPServer(){InitializeComponent();myAddOnline = AddOnline;myRcvMsg = RecMsg;myFileSave = FileSave;}//创建套接字Socket sock = null;//创建负责监听客户端连接的线程Thread threadListen = null;//创建URL与Socket的字典集合Dictionary<string, Socket> DicSocket = new Dictionary<string, Socket>();AddOnLineDelegate myAddOnline;RecMsgDelegate myRcvMsg;FileSaveDelegate myFileSave;#region 开始监听/// <summary>/// 开始监听/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_StartServer_Click(object sender, EventArgs e){//创建负责监听的套接字,注意其中参数:IPV4 字节流 TCPsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);IPAddress address = IPAddress.Parse(this.txt_IP.Text.Trim());//根据IPAddress以及端口号创建IPE对象IPEndPoint endpoint = new IPEndPoint(address, int.Parse(this.txt_Port.Text.Trim()));try{sock.Bind(endpoint);Invoke(myRcvMsg, "服务器开启成功!");MessageBox.Show("开启服务成功!", "打开服务");}catch (Exception ex){MessageBox.Show("开启服务失败" + ex.Message, "打开服务");return;}sock.Listen(10);threadListen = new Thread(ListenConnecting);threadListen.IsBackground = true;threadListen.Start();this.btn_StartServer.Enabled = false;}#endregion#region 监听线程/// <summary>/// 监听线程/// </summary>private void ListenConnecting(){while (true){//一旦监听到一个客户端的连接,将会创建一个与该客户端连接的套接字Socket sockClient = sock.Accept();string client = sockClient.RemoteEndPoint.ToString();DicSocket.Add(client, sockClient);Invoke(myAddOnline, client, true);Invoke(myRcvMsg, client + "上线了!");//开启接受线程Thread thr = new Thread(ReceiveMsg);thr.IsBackground = true;thr.Start(sockClient);}}#endregion#region 接收线程/// <summary>/// 接收线程/// </summary>/// <param name="sockClient"></param>private void ReceiveMsg(object sockClient){Socket sckclient = sockClient as Socket;while (true){//定义一个2M缓冲区byte[] arrMsgRec = new byte[1024 * 1024 * 2];int length = -1;try{length = sckclient.Receive(arrMsgRec);}catch (Exception){string str = sckclient.RemoteEndPoint.ToString();Invoke(myRcvMsg, str + "下线了!");//从列表中移除URLInvoke(myAddOnline, str, false);DicSocket.Remove(str);break;}if (length == 0){string str = sckclient.RemoteEndPoint.ToString();Invoke(myRcvMsg, str + "下线了!");//从列表中移除URLInvoke(myAddOnline, str, false);DicSocket.Remove(str);break;}else{if (arrMsgRec[0] == 0){string strMsg = Encoding.UTF8.GetString(arrMsgRec, 1, length-1);string Msg = "[接收]     " + sckclient.RemoteEndPoint.ToString() + "     " + strMsg;Invoke(myRcvMsg, Msg);}if (arrMsgRec[0] == 1){Invoke(myFileSave, arrMsgRec,length);}}}}#endregion#region 委托方法体private void AddOnline(string url, bool bl){if (bl){this.lbOnline.Items.Add(url);}else{this.lbOnline.Items.Remove(url);}}private void RecMsg(string str){this.txt_Rcv.AppendText(str + Environment.NewLine);}private void FileSave(byte[] bt, int length){try{SaveFileDialog sfd = new SaveFileDialog();sfd.Filter = "word files(*.docx)|*.docx|txt files(*.txt)|*.txt|xls files(*.xls)|*.xls|All files(*.*)|*.*";if (sfd.ShowDialog() == DialogResult.OK){string fileSavePath = sfd.FileName;using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)){fs.Write(bt, 1, length - 1);Invoke(new Action(() => this.txt_Rcv.AppendText("[保存]     保存文件成功" + fileSavePath + Environment.NewLine)));}}}catch (Exception ex){MessageBox.Show("保存异常" + ex.Message, "保存文件出现异常");}}#endregion#region 发送消息/// <summary>/// 发送消息/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SendToSingle_Click(object sender, EventArgs e){string StrMsg = this.txt_Send.Text.Trim();byte[] arrMsg = Encoding.UTF8.GetBytes(StrMsg);byte[] arrSend = new byte[arrMsg.Length + 1];arrSend[0] = 0;Buffer.BlockCopy(arrMsg, 0, arrSend, 1, arrMsg.Length);if (this.lbOnline.SelectedItems.Count == 0){MessageBox.Show("请选择你要发送的对象!", "发送提示");return;}else{foreach (string item in this.lbOnline.SelectedItems){DicSocket[item].Send(arrSend);string Msg = "[发送]     " + item + "     " + StrMsg;Invoke(myRcvMsg, Msg);}}}#endregion#region 群发消息/// <summary>/// 群发消息/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SendToAll_Click(object sender, EventArgs e){string StrMsg = this.txt_Send.Text.Trim();byte[] arrMsg = Encoding.UTF8.GetBytes(StrMsg);byte[] arrSend = new byte[arrMsg.Length + 1];arrSend[0] = 0;Buffer.BlockCopy(arrMsg, 0, arrSend, 1, arrMsg.Length);foreach (string item in this.DicSocket.Keys){DicSocket[item].Send(arrSend);string Msg = "[发送]     " + item + "     " + StrMsg;Invoke(myRcvMsg, Msg);}Invoke(myRcvMsg, "[群发]     群发完毕!");}#endregion#region 打开客户端/// <summary>/// 打开客户端/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_Client_Click(object sender, EventArgs e){FrmTCPClient objFrm = new FrmTCPClient();objFrm.Show();}#endregion#region 选择文件/// <summary>/// 选择文件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SelectFile_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.InitialDirectory = "D:\\";if (ofd.ShowDialog() == DialogResult.OK){this.txt_SelectFile.Text = ofd.FileName;}}#endregion#region 发送文件/// <summary>/// 发送文件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SendFile_Click(object sender, EventArgs e){if (string.IsNullOrEmpty(txt_SelectFile.Text)){MessageBox.Show("请选择您要发送的文件!", "发送文件提示");return;}string online = this.lbOnline.Text.Trim();if (string.IsNullOrEmpty(online)){MessageBox.Show("请选择您要发送的对象!", "发送文件提示");return;}using (FileStream fs = new FileStream(txt_SelectFile.Text, FileMode.Open)){string filename = Path.GetFileName(txt_SelectFile.Text);string StrMsg = "发送文件为:" + filename;byte[] arrMsg = Encoding.UTF8.GetBytes(StrMsg);byte[] arrSend= new byte[arrMsg.Length + 1];arrSend[0] =0;Buffer.BlockCopy(arrMsg, 0, arrSend, 1, arrMsg.Length);DicSocket[online].Send(arrSend);byte[] arrfileSend = new byte[1024 * 1024 * 2];int length = fs.Read(arrfileSend, 0, arrfileSend.Length);byte[] arrfile = new byte[length + 1];arrfile[0] = 1;Buffer.BlockCopy(arrfileSend, 0, arrfile, 1, length);DicSocket[online].Send(arrfile);}}#endregion}
}

        2、客户端FrmClient.cs文件

           FrmClient.cs窗体

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace SocketTCP
{delegate void FileSaveDelegate(byte[] bt,int length);public partial class FrmTCPClient : Form{public FrmTCPClient(){InitializeComponent();MyFileSave = FileSave;}//Socket对象Socket sockClient = null;//接收线程Thread thrClient = null;//运行标志位private bool IsRunning = true;//文件保存委托对象FileSaveDelegate MyFileSave;#region 连接服务器/// <summary>/// 连接服务器/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_Connect_Click(object sender, EventArgs e){IPAddress address = IPAddress.Parse(this.txt_IP.Text.Trim());IPEndPoint Ipe = new IPEndPoint(address, int.Parse(this.txt_Port.Text.Trim()));sockClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);try{this.txt_Rcv.AppendText("与服务器连接中......" + Environment.NewLine);sockClient.Connect(Ipe);}catch (Exception ex){MessageBox.Show("连接失败" + ex.Message, "建立连接");return;}this.txt_Rcv.AppendText("与服务器连接成功" + Environment.NewLine);this.btn_Connect.Enabled = false;thrClient = new Thread(ReceiceMsg);thrClient.IsBackground = true;thrClient.Start();}#endregion#region 接收消息/// <summary>/// 接收消息/// </summary>private void ReceiceMsg(){while (IsRunning){//定义一个2M缓冲区byte[] arrMsgRec = new byte[1024 * 1024 * 2];int length = -1;try{length = sockClient.Receive(arrMsgRec);}catch (SocketException){break;}catch (Exception ex){Invoke(new Action(() => this.txt_Rcv.AppendText("断开连接" + ex.Message + Environment.NewLine)));break;}if (length > 0){//表示接受到的为消息类型if (arrMsgRec[0] == 0){string strMsg = Encoding.UTF8.GetString(arrMsgRec, 1, length-1);string Msg = "[接收]     " + strMsg + Environment.NewLine;Invoke(new Action(() => this.txt_Rcv.AppendText(Msg)));}//表示接收到的为文件类型if (arrMsgRec[0] == 1){Invoke(MyFileSave, arrMsgRec,length);}}}}#endregion#region 委托方法体private void FileSave(byte[] bt, int length){try{SaveFileDialog sfd = new SaveFileDialog();sfd.Filter = "word files(*.docx)|*.docx|txt files(*.txt)|*.txt|xls files(*.xls)|*.xls|All files(*.*)|*.*";if (sfd.ShowDialog() == DialogResult.OK){string fileSavePath = sfd.FileName;using (FileStream fs = new FileStream(fileSavePath, FileMode.Create)){fs.Write(bt, 1, length - 1);Invoke(new Action(() => this.txt_Rcv.AppendText("[保存]     保存文件成功" + fileSavePath+Environment.NewLine)));}}}catch (Exception ex){MessageBox.Show("保存异常" + ex.Message, "保存文件出现异常");}}#endregion#region 发送消息/// <summary>/// 发送消息/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_Send_Click(object sender, EventArgs e){string strMsg = "来自" + this.txt_Name.Text.Trim() + ":  " + this.txt_Send.Text.Trim();byte[] arrMsg = Encoding.UTF8.GetBytes(strMsg);byte[] arrSend = new byte[arrMsg.Length + 1];arrSend[0] = 0;Buffer.BlockCopy(arrMsg, 0, arrSend, 1, arrMsg.Length);sockClient.Send(arrSend);Invoke(new Action(() => this.txt_Rcv.AppendText("[发送]     " + this.txt_Send.Text.Trim() + Environment.NewLine)));}#endregion#region 窗体关闭事件/// <summary>/// 窗体关闭事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void FrmTCPClient_FormClosing(object sender, FormClosingEventArgs e){IsRunning = false;sockClient?.Close();}#endregion#region 选择文件/// <summary>/// 选择文件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SelectFile_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.InitialDirectory = "D:\\";if (ofd.ShowDialog() == DialogResult.OK){this.txt_SelectFile.Text = ofd.FileName;}}#endregion#region 发送文件/// <summary>/// 发送文件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btn_SendFile_Click(object sender, EventArgs e){if (string.IsNullOrEmpty(txt_SelectFile.Text)){MessageBox.Show("请选择您要发送的文件!", "发送文件提示");return;}using (FileStream fs = new FileStream(txt_SelectFile.Text, FileMode.Open)){string filename = Path.GetFileName(txt_SelectFile.Text);string StrMsg = "发送文件为:" + filename;byte[] arrMsg = Encoding.UTF8.GetBytes(StrMsg);byte[] arrSend = new byte[arrMsg.Length + 1];arrSend[0] = 0;Buffer.BlockCopy(arrMsg, 0, arrSend, 1, arrMsg.Length);sockClient.Send(arrSend);byte[] arrfileSend = new byte[1024 * 1024 * 2];int length = fs.Read(arrfileSend, 0, arrfileSend.Length);byte[] arrfile = new byte[length + 1];arrfile[0] = 1;Buffer.BlockCopy(arrfileSend, 0, arrfile, 1, length);sockClient.Send(arrfile);}}#endregion}
}

        3、启动文件Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;namespace SocketTCP
{static class Program{/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new FrmTCPServer());}}
}

结果展示 

相关文章:

Socket编程详解(一)服务端与客户端的双向对话

目录 预备知识 视频教程 项目前准备知识点 1、服务器端程序的编写步骤 2、客户端程序编写步骤 代码部分 1、服务端FrmServer.cs文件 2、客户端FrmClient.cs文件 3、启动文件Program.cs 结果展示 预备知识 请查阅博客http://t.csdnimg.cn/jE4Tp 视频教程 链接&#…...

使用Python实现深度学习模型:强化学习与深度Q网络(DQN)

深度Q网络(Deep Q-Network,DQN)是结合深度学习与强化学习的一种方法,用于解决复杂的决策问题。本文将详细介绍如何使用Python实现DQN,主要包括以下几个方面: 强化学习简介DQN算法简介环境搭建DQN模型实现模型训练与评估1. 强化学习简介 强化学习是一种训练智能体(agent…...

Py-Spy、Scalene 和 VizTracer 的对比分析

在前几篇文章中&#xff0c;我们详细介绍了如何使用 py-spy、scalene 和 viztracer 进行性能分析和优化。今天&#xff0c;我们将对这三个性能分析工具进行详细对比&#xff0c;帮助你选择最适合你的工具。 工具简介 Py-Spy&#xff1a; 实时性能分析&#xff1a;Py-Spy 可以…...

软考架构师考试内容

软考系统架构设计师考试是中国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试&#xff08;简称软考&#xff09;中的一项高级资格考试&#xff0c;旨在评估考生是否具备系统架构设计的能力。根据提供的参考资料&#xff0c;考试内容主要包括以下几个方面&#…...

【MySQL基础篇】概述及SQL指令:DDL及DML

数据库是一个按照数据结构来组织、存储和管理数据的仓库。以下是对数据库概念的详细解释&#xff1a;定义与基本概念&#xff1a; 数据库是长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集合。 数据库不仅仅是数据的简单堆积&#xff0c;而是遵循一定的规则…...

计算机网络 —— 网络字节序

网络字节序 1、网络字节序 (Network Byte Order)和本机转换 1、大端、小端字节序 “大端” 和” 小端” 表示多字节值的哪一端存储在该值的起始地址处&#xff1b;小端存储在起始地址处&#xff0c;即是小端字节序&#xff1b;大端存储在起始地址处&#xff0c;即是大端字节…...

区块链不可能三角

区块链不可能三角&#xff1a;探索去中心化、安全与可扩展性的权衡 引言 区块链技术自诞生以来&#xff0c;以其去中心化、透明、安全等特点吸引了全球的关注&#xff0c;成为金融科技领域的重要革新力量。然而&#xff0c;随着区块链应用的日益广泛&#xff0c;一个核心问题…...

新手第一个漏洞复现:MS17-010(永恒之蓝)

文章目录 漏洞原理漏洞影响范围复现环境复现步骤 漏洞原理 漏洞出现在Windows SMB v1中的内核态函数srv!SrvOs2FeaListToNt在处理FEA&#xff08;File Extended Attributes&#xff09;转换时。该函数在将FEA list转换成NTFEA&#xff08;Windows NT FEA&#xff09;list前&am…...

代码随想录Day64

98.所有可达路径 题目&#xff1a;98. 所有可达路径 (kamacoder.com) 思路&#xff1a;果断放弃 答案 import java.util.*;public class Main {private static List<List<Integer>> adjList;private static List<List<Integer>> allPaths;private sta…...

Angular 指令

Angular 指令是 Angular 框架中的一项核心功能&#xff0c;它允许开发人员扩展 HTML 的功能&#xff0c;并创建可复用的组件和行为。以下是一些常见的 Angular 指令&#xff1a; 1. 组件指令 (Component Directives) 组件指令是最常用的一种指令&#xff0c;用于创建可复用的 U…...

移动端 UI 风格,书写华丽篇章

移动端 UI 风格&#xff0c;书写华丽篇章...

flutter开发实战-ListWheelScrollView与自定义TimePicker时间选择器

flutter开发实战-ListWheelScrollView与自定义TimePicker 最近在使用时间选择器的时候&#xff0c;需要自定义一个TimePicker效果&#xff0c;当然这里就使用了ListWheelScrollView。ListWheelScrollView与ListView类似&#xff0c;但ListWheelScrollView渲染效果类似滚筒效果…...

stable diffusion 模型和lora融合

炜哥的AI学习笔记——SuperMerger插件学习 - 哔哩哔哩接下来学习的插件名字叫做 SuperMerger,它的作用正如其名,可以融合大模型或者 LoRA,一般来说会结合之前的插件 LoRA Block Weight 使用,在调整完成 LoRA 模型的权重后使用改插件进行重新打包。除了 LoRA ,Checkpoint 也…...

Spring Boot中的分布式缓存方案

Spring Boot中的分布式缓存方案 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨在Spring Boot应用中实现分布式缓存的方案&#xff0c;以提升系统…...

AI写作革命:如何用AI工具轻松搞定700+学科的论文?

不知道大家有没有发现&#xff0c;随着人工智能技术的快速发展&#xff0c;AI工具正逐渐渗透到我们日常生活的各个方面&#xff0c;极大地提高了我们的工作和学习效率。无论是AI写作、AI绘画、AI思维导图&#xff0c;还是AI幻灯片制作&#xff0c;这些工具已成为我们不可或缺的…...

v-for中key的原理以及用法

在 Vue.js 中&#xff0c;v-for 指令用于基于源数据多次渲染元素或模板块。当使用 v-for 渲染列表时&#xff0c;为每个列表项提供一个唯一的 key 属性是非常重要的。key 的主要作用是帮助 Vue 跟踪每个节点的身份&#xff0c;从而重用和重新排序现有元素。 先来张原理图&#…...

基于强化学习的目标跟踪论文合集

文章目录 2020UAV Maneuvering Target Tracking in Uncertain Environments Based on Deep Reinforcement Learning and Meta-LearningUAV Target Tracking in Urban Environments Using Deep Reinforcement Learning 2021Research on Vehicle Dispatch Problem Based on Kuhn-…...

高质量AIGC/ChatGPT/大模型资料分享

2023年要说科技圈什么最火爆&#xff0c;一定是ChatGPT、AIGC&#xff08;人工智能生成内容&#xff09;和大型语言模型。这些技术前沿如同科技世界的新潮流&#xff0c;巨浪拍岸&#xff0c;引发各界关注。ChatGPT的互动性和逼真度让人们瞠目&#xff0c;它能与用户展开流畅对…...

使用Python进行Socket接口测试

大家好&#xff0c;在现代软件开发中&#xff0c;网络通信是不可或缺的一部分。无论是传输数据、获取信息还是实现实时通讯&#xff0c;都离不开可靠的网络连接和有效的数据交换机制。而在网络编程的基础中&#xff0c;Socket&#xff08;套接字&#xff09;技术扮演了重要角色…...

C++编程逻辑讲解step by step:存折和信用卡类。

题目 存折和信用卡类&#xff0c;信用卡是一种存折&#xff0c;可以透支&#xff0c;可以存款。 代码 #include<iostream> #include<string> using namespace std; class passbook {public: passbook(string nam,int n,float m) {namenam; numn; balancem; } vo…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案

在移动互联网营销竞争白热化的当下&#xff0c;推客小程序系统凭借其裂变传播、精准营销等特性&#xff0c;成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径&#xff0c;助力开发者打造具有市场竞争力的营销工具。​ 一、系统核心功能架构&…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...

Easy Excel

Easy Excel 一、依赖引入二、基本使用1. 定义实体类&#xff08;导入/导出共用&#xff09;2. 写 Excel3. 读 Excel 三、常用注解说明&#xff08;完整列表&#xff09;四、进阶&#xff1a;自定义转换器&#xff08;Converter&#xff09; 其它自定义转换器没生效 Easy Excel在…...