C#使用TCP-S7协议读写西门子PLC(三)
接上篇
C#使用TCP-S7协议读写西门子PLC(二)-CSDN博客
这里我们进行封装读写西门子PLC的S7协议命令以及连接西门子PLC并两次握手
新建部分类文件SiemensS7ProtocolUtil.ReadWrite.cs
主要方法:
连接西门子PLC并发送两次握手。两次握手成功后,才真正连接到PLC
public OperateResult ConnectPlcAndHandshake(SiemensPlcCategory siemensPlcCategory, IPEndPoint endPoint, int timeout = 3000)
生成一个写入字节数据的指令
public static OperateResult<byte[]> BuildWriteByteCommand(OperateResult<byte, int, ushort> analysis, byte[] data)
生成一个读取字数据指令头的通用方法【一个字Word占用两个字节Byte】
public static OperateResult<byte[]> BuildReadCommand(OperateResult<byte, int, ushort>[] address, ushort[] length)
SiemensS7ProtocolUtil.ReadWrite.cs源程序如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;namespace PlcSiemesS7Demo
{/// <summary>/// 西门子S7协议,封装读写命令/// 关键方法:连接PLC并发送两次握手、生成写PLC命令,生成读PLC命令/// (1).public OperateResult ConnectPlcAndHandshake(SiemensPlcCategory siemensPlcCategory, IPEndPoint endPoint, int timeout = 3000)/// (2).public static OperateResult<byte[]> BuildWriteByteCommand(OperateResult<byte, int, ushort> analysis, byte[] data)/// (3).BuildReadCommand(OperateResult<byte, int, ushort>[] address, ushort[] length)/// </summary>public partial class SiemensS7ProtocolUtil{#region 西门子S7协议握手【两次握手】命令,固定.不同型号的PLC握手命令有少许不同private byte[] plcHead1 = new byte[22]{0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC0,0x01,0x0A,0xC1,0x02,0x01,0x02,0xC2,0x02,0x01,0x00};private byte[] plcHead2 = new byte[25]{0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0x04,0x00,0x00,0x08,0x00,0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x01,0xE0};private byte[] plcHead1_200smart = new byte[22]{0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,0x00,0x01,0x00,0xC1,0x02,0x10,0x00,0xC2,0x02,0x03,0x00,0xC0,0x01,0x0A};private byte[] plcHead2_200smart = new byte[25]{0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,0x01,0x00,0x00,0xCC,0xC1,0x00,0x08,0x00,0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0};#endregion/// <summary>/// 连接西门子PLC并发送两次握手。两次握手成功后,才真正连接到PLC/// 使用网络终结点和PLC型号枚举进行连接/// </summary>/// <param name="siemensPlcCategory"></param>/// <param name="endPoint"></param>/// <param name="timeout"></param>/// <returns></returns>public OperateResult ConnectPlcAndHandshake(SiemensPlcCategory siemensPlcCategory, IPEndPoint endPoint, int timeout = 3000){isConnected = false;this.SiemensPlcCategory = siemensPlcCategory;switch (siemensPlcCategory){case SiemensPlcCategory.S1200:case SiemensPlcCategory.S1500:plcHead1[21] = 0;break;case SiemensPlcCategory.S300:plcHead1[21] = 2;break;case SiemensPlcCategory.S400:plcHead1[21] = 3;plcHead1[17] = 0x00;break;case SiemensPlcCategory.S200Smart:plcHead1 = plcHead1_200smart;plcHead2 = plcHead2_200smart;break;default:plcHead1[18] = 0;break;}// 重新连接之前,先将旧的数据进行清空CoreSocket?.Close();OperateResult<Socket> result = ConnectPlc(endPoint, timeout);if (result.IsSuccess){// 第一次握手 -> First handshakeOperateResult<byte[]> read_first = SendDataAndWaitResult(result.Content, plcHead1);if (!read_first.IsSuccess){RecordLogEvent?.Invoke($"第一次握手出错:{read_first.Message}");return read_first;}// 第二次握手 -> Second handshakeOperateResult<byte[]> read_second = SendDataAndWaitResult(result.Content, plcHead2);if (!read_second.IsSuccess){RecordLogEvent?.Invoke($"第二次握手出错:{read_second.Message}");return read_second;}// 返回成功的信号 CoreSocket = result.Content;result.IsSuccess = true;isConnected = true;RecordLogEvent?.Invoke($"连接PLC【{endPoint}】成功并且两次握手成功");}else{result.Content?.Close();CoreSocket = null;result.IsSuccess = false;}return result;}/// <summary>/// 连接西门子PLC并发送两次握手。两次握手成功后,才真正连接到PLC/// 使用IP地址和端口【默认102】和PLC型号枚举进行连接/// </summary>/// <param name="siemensPlcCategory"></param>/// <param name="ipAddress"></param>/// <param name="port"></param>/// <param name="timeout"></param>/// <returns></returns>public OperateResult ConnectPlcAndHandshake(SiemensPlcCategory siemensPlcCategory, string ipAddress, int port = 102, int timeout = 3000){return ConnectPlcAndHandshake(siemensPlcCategory, new IPEndPoint(IPAddress.Parse(ipAddress), port), timeout);}private OperateResult<byte[]> Read(OperateResult<byte, int, ushort>[] address, ushort[] length){// 构建指令 -> Build read commandOperateResult<byte[]> command = BuildReadCommand(address, length);if (!command.IsSuccess) return command;// 核心交互 -> Core InteractionsOperateResult<byte[]> read = SendDataAndWaitResult(command.Content);if (!read.IsSuccess) return read;// 分析结果 -> Analysis resultsint receiveCount = 0;for (int i = 0; i < length.Length; i++){receiveCount += length[i];}if (read.Content.Length >= 21 && read.Content[20] == length.Length){byte[] buffer = new byte[receiveCount];int kk = 0;int ll = 0;for (int ii = 21; ii < read.Content.Length; ii++){if ((ii + 1) < read.Content.Length){if (read.Content[ii] == 0xFF && read.Content[ii + 1] == 0x04){Array.Copy(read.Content, ii + 4, buffer, ll, length[kk]);ii += length[kk] + 3;ll += length[kk];kk++;}}}return OperateResult.CreateSuccessResult(buffer);}else{return new OperateResult<byte[]>() { ErrorCode = read.ErrorCode, Message = "数据块长度校验失败,请检查是否开启put/get以及关闭db块优化" };}}private OperateResult<byte[]> ReadBitFromPLC(OperateResult<byte, int, ushort> analysis){// 指令生成 -> Build bit read commandOperateResult<byte[]> command = BuildBitReadCommand(analysis);if (!command.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(command);// 核心交互 -> Core interactiveOperateResult<byte[]> read = SendDataAndWaitResult(command.Content);if (!read.IsSuccess) return read;// 分析结果 -> Analysis read resultint receiveCount = 1;if (read.Content.Length >= 21 && read.Content[20] == 1){byte[] buffer = new byte[receiveCount];if (22 < read.Content.Length){if (read.Content[21] == 0xFF && read.Content[22] == 0x03){buffer[0] = read.Content[25];}}return OperateResult.CreateSuccessResult(buffer);}else{return new OperateResult<byte[]>(read.ErrorCode, "数据块长度校验失败,请检查是否开启put/get以及关闭db块优化");}}/// <summary>/// 基础的写入数据的操作支持 -> Operational support for the underlying write data/// </summary>/// <param name="entireValue">完整的字节数据 -> Full byte data</param>/// <returns>是否写入成功的结果对象 -> Whether to write a successful result object</returns>private OperateResult WriteBase(byte[] entireValue){OperateResult<byte[]> write = SendDataAndWaitResult(entireValue);if (!write.IsSuccess) return write;if (write.Content[write.Content.Length - 1] != 0xFF){// 写入异常 -> WriteErrorreturn new OperateResult(write.Content[write.Content.Length - 1], "写入数据异常,代号为:" + write.Content[write.Content.Length - 1]);}else{return OperateResult.CreateSuccessResult();}}/// <summary>/// 生成一个写入字节数据的指令 -> Generate an instruction to write byte data/// </summary>/// <param name="analysis">内存区域标识,起始地址*8,DB块编号 </param>/// <param name="data">原始的字节数据 -> Raw byte data</param>/// <returns>包含结果对象的报文 -> Message containing the result object</returns>public static OperateResult<byte[]> BuildWriteByteCommand(OperateResult<byte, int, ushort> analysis, byte[] data){byte[] _PLCCommand = new byte[35 + data.Length];_PLCCommand[0] = 0x03;_PLCCommand[1] = 0x00;// 长度 -> Length_PLCCommand[2] = (byte)((35 + data.Length) / 256);_PLCCommand[3] = (byte)((35 + data.Length) % 256);// 固定 -> Fixed_PLCCommand[4] = 0x02;_PLCCommand[5] = 0xF0;_PLCCommand[6] = 0x80;_PLCCommand[7] = 0x32;// 命令 发 -> command to send_PLCCommand[8] = 0x01;// 标识序列号 -> Identification serial Number_PLCCommand[9] = 0x00;_PLCCommand[10] = 0x00;_PLCCommand[11] = 0x00;_PLCCommand[12] = 0x01;// 固定 -> Fixed_PLCCommand[13] = 0x00;_PLCCommand[14] = 0x0E;// 写入长度+4 -> Write Length +4_PLCCommand[15] = (byte)((4 + data.Length) / 256);_PLCCommand[16] = (byte)((4 + data.Length) % 256);// 读写指令 -> Read and write instructions_PLCCommand[17] = 0x05;// 写入数据块个数 -> Number of data blocks written_PLCCommand[18] = 0x01;// 固定,返回数据长度 -> Fixed, return data length_PLCCommand[19] = 0x12;_PLCCommand[20] = 0x0A;_PLCCommand[21] = 0x10;// 写入方式,1是按位,2是按字 -> Write mode, 1 is bitwise, 2 is by word_PLCCommand[22] = 0x02;// 写入数据的个数 -> Number of Write Data_PLCCommand[23] = (byte)(data.Length / 256);_PLCCommand[24] = (byte)(data.Length % 256);// DB块编号,如果访问的是DB块的话 -> DB block number, if you are accessing a DB block_PLCCommand[25] = (byte)(analysis.Content3 / 256);_PLCCommand[26] = (byte)(analysis.Content3 % 256);// 写入数据的类型 -> Types of writing data_PLCCommand[27] = analysis.Content1;// 偏移位置 -> Offset position 因65535*8 即0x07 FF F8 偏移地址占用三个字节:下面注释的三行等价于BitConverter.GetBytes(Int32) //_PLCCommand[28] = (byte)(analysis.Content2 / 256 / 256 % 256);//_PLCCommand[29] = (byte)(analysis.Content2 / 256 % 256);//_PLCCommand[30] = (byte)(analysis.Content2 % 256);byte[] offsetAddress = BitConverter.GetBytes(analysis.Content2);_PLCCommand[28] = offsetAddress[2];_PLCCommand[29] = offsetAddress[1];_PLCCommand[30] = offsetAddress[0];// 按字写入 -> Write by Word_PLCCommand[31] = 0x00;_PLCCommand[32] = 0x04;// 按位计算的长度 -> The length of the bitwise calculation_PLCCommand[33] = (byte)(data.Length * 8 / 256);_PLCCommand[34] = (byte)(data.Length * 8 % 256);data.CopyTo(_PLCCommand, 35);return OperateResult.CreateSuccessResult(_PLCCommand);}public static OperateResult<byte[]> BuildWriteBitCommand(OperateResult<byte, int, ushort> analysis, bool data){//OperateResult<byte, int, ushort> analysis = AnalysisAddress(address);if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysis);byte[] buffer = new byte[1];buffer[0] = data ? (byte)0x01 : (byte)0x00;byte[] _PLCCommand = new byte[35 + buffer.Length];_PLCCommand[0] = 0x03;_PLCCommand[1] = 0x00;// 长度 -> length_PLCCommand[2] = (byte)((35 + buffer.Length) / 256);_PLCCommand[3] = (byte)((35 + buffer.Length) % 256);// 固定 -> fixed_PLCCommand[4] = 0x02;_PLCCommand[5] = 0xF0;_PLCCommand[6] = 0x80;_PLCCommand[7] = 0x32;// 命令 发 -> command to send_PLCCommand[8] = 0x01;// 标识序列号 -> Identification serial Number_PLCCommand[9] = 0x00;_PLCCommand[10] = 0x00;_PLCCommand[11] = 0x00;_PLCCommand[12] = 0x01;// 固定 -> fixed_PLCCommand[13] = 0x00;_PLCCommand[14] = 0x0E;// 写入长度+4 -> Write Length +4_PLCCommand[15] = (byte)((4 + buffer.Length) / 256);_PLCCommand[16] = (byte)((4 + buffer.Length) % 256);// 命令起始符 -> Command start character_PLCCommand[17] = 0x05;// 写入数据块个数 -> Number of data blocks written_PLCCommand[18] = 0x01;_PLCCommand[19] = 0x12;_PLCCommand[20] = 0x0A;_PLCCommand[21] = 0x10;// 写入方式,1是按位,2是按字 -> Write mode, 1 is bitwise, 2 is by word_PLCCommand[22] = 0x01;// 写入数据的个数 -> Number of Write Data_PLCCommand[23] = (byte)(buffer.Length / 256);_PLCCommand[24] = (byte)(buffer.Length % 256);// DB块编号,如果访问的是DB块的话 -> DB block number, if you are accessing a DB block_PLCCommand[25] = (byte)(analysis.Content3 / 256);_PLCCommand[26] = (byte)(analysis.Content3 % 256);// 写入数据的类型 -> Types of writing data_PLCCommand[27] = analysis.Content1;// 偏移位置 -> Offset position_PLCCommand[28] = (byte)(analysis.Content2 / 256 / 256);_PLCCommand[29] = (byte)(analysis.Content2 / 256);_PLCCommand[30] = (byte)(analysis.Content2 % 256);// 按位写入 -> Bitwise Write_PLCCommand[31] = 0x00;_PLCCommand[32] = 0x03;// 按位计算的长度 -> The length of the bitwise calculation_PLCCommand[33] = (byte)(buffer.Length / 256);_PLCCommand[34] = (byte)(buffer.Length % 256);buffer.CopyTo(_PLCCommand, 35);return OperateResult.CreateSuccessResult(_PLCCommand);}/// <summary>/// 解析地址,返回元组【地址类型,起始地址,DB块编号】/// </summary>/// <param name="plcRegisterCategory">寄存器类型</param>/// <param name="offsetAddress">偏移量,偏移地址</param>/// <param name="dbNumber">DB块号</param>/// <param name="bitIndex">位索引0~7</param>/// <returns></returns>private static OperateResult<byte, int, ushort> AnalysisAddress(PlcRegisterCategory plcRegisterCategory, ushort offsetAddress, ushort dbNumber = 0, int bitIndex = 0){//地址类型,起始地址,DB块编号OperateResult<byte, int, ushort> result = new OperateResult<byte, int, ushort>();result.Content3 = 0;switch (plcRegisterCategory){case PlcRegisterCategory.DB:result.Content1 = 0x84;result.Content2 = offsetAddress * 8 + bitIndex;result.Content3 = dbNumber;break;case PlcRegisterCategory.M:result.Content1 = 0x83;result.Content2 = offsetAddress * 8 + bitIndex;break;case PlcRegisterCategory.Input:result.Content1 = 0x81;result.Content2 = offsetAddress * 8 + bitIndex;break;case PlcRegisterCategory.Quit:result.Content1 = 0x82;result.Content2 = offsetAddress * 8 + bitIndex;break;case PlcRegisterCategory.T:result.Content1 = 0x1D;result.Content2 = offsetAddress * 8 + bitIndex;break;case PlcRegisterCategory.C:result.Content1 = 0x1C;result.Content2 = offsetAddress * 8 + bitIndex;break;case PlcRegisterCategory.V:result.Content1 = 0x84;result.Content2 = offsetAddress * 8 + bitIndex;result.Content3 = 1;break;default:result.Message = "输入的类型不支持,请重新输入";result.Content1 = 0;result.Content2 = 0;result.Content3 = 0;return result;}result.IsSuccess = true;return result;}/// <summary>/// 生成一个读取字数据指令头的通用方法【一个字Word占用两个字节Byte】 ->/// A general method for generating a command header to read a Word data/// </summary>/// <param name="address">起始地址,例如M100,I0,Q0,DB2.100 ->/// Start address, such as M100,I0,Q0,DB2.100</param>/// <param name="length">读取数据长度 -> Read Data length</param>/// <returns>包含结果对象的报文 -> Message containing the result object</returns>public static OperateResult<byte[]> BuildReadCommand(OperateResult<byte, int, ushort>[] address, ushort[] length){if (address == null) throw new NullReferenceException("address");if (length == null) throw new NullReferenceException("count");if (address.Length != length.Length) throw new Exception("两个参数的个数不一致");if (length.Length > 19) throw new Exception("读取的数组数量不允许大于19");int readCount = length.Length;byte[] _PLCCommand = new byte[19 + readCount * 12];// ======================================================================================_PLCCommand[0] = 0x03; // 报文头 -> Head_PLCCommand[1] = 0x00;_PLCCommand[2] = (byte)(_PLCCommand.Length / 256); // 长度 -> Length_PLCCommand[3] = (byte)(_PLCCommand.Length % 256);_PLCCommand[4] = 0x02; // 固定 -> Fixed_PLCCommand[5] = 0xF0;_PLCCommand[6] = 0x80;_PLCCommand[7] = 0x32; // 协议标识 -> Protocol identification_PLCCommand[8] = 0x01; // 命令:发 -> Command: Send_PLCCommand[9] = 0x00; // 冗余标识(保留)-> redundancy identification (reserved): 0x0000;_PLCCommand[10] = 0x00; // protocol data unit reference; it’s increased by request event;_PLCCommand[11] = 0x00;_PLCCommand[12] = 0x01; // 参数命令数据总长度 -> Parameter command Data total length_PLCCommand[13] = (byte)((_PLCCommand.Length - 17) / 256);_PLCCommand[14] = (byte)((_PLCCommand.Length - 17) % 256);_PLCCommand[15] = 0x00; // 读取内部数据时为00,读取CPU型号为Data数据长度 -> Read internal data is 00, read CPU model is data length_PLCCommand[16] = 0x00;// =====================================================================================_PLCCommand[17] = 0x04; // 读写指令,04读,05写 -> Read-write instruction, 04 read, 05 Write_PLCCommand[18] = (byte)readCount; // 读取数据块个数 -> Number of data blocks readfor (int ii = 0; ii < readCount; ii++){//===========================================================================================// 指定有效值类型 -> Specify a valid value type_PLCCommand[19 + ii * 12] = 0x12;// 接下来本次地址访问长度 -> The next time the address access length_PLCCommand[20 + ii * 12] = 0x0A;// 语法标记,ANY -> Syntax tag, any_PLCCommand[21 + ii * 12] = 0x10;// 按字为单位 -> by word_PLCCommand[22 + ii * 12] = 0x02;// 访问数据的个数 -> Number of Access data_PLCCommand[23 + ii * 12] = (byte)(length[ii] / 256);_PLCCommand[24 + ii * 12] = (byte)(length[ii] % 256);// DB块编号,如果访问的是DB块的话 -> DB block number, if you are accessing a DB block_PLCCommand[25 + ii * 12] = (byte)(address[ii].Content3 / 256);_PLCCommand[26 + ii * 12] = (byte)(address[ii].Content3 % 256);// 访问数据类型 -> Accessing data types_PLCCommand[27 + ii * 12] = address[ii].Content1;// 偏移位置 -> Offset position_PLCCommand[28 + ii * 12] = (byte)(address[ii].Content2 / 256 / 256 % 256);_PLCCommand[29 + ii * 12] = (byte)(address[ii].Content2 / 256 % 256);_PLCCommand[30 + ii * 12] = (byte)(address[ii].Content2 % 256);}return OperateResult.CreateSuccessResult(_PLCCommand);}/// <summary>/// 生成一个位读取数据指令头的通用方法 ->/// A general method for generating a bit-read-Data instruction header/// </summary>/// <param name="address">起始地址,例如M100.0,I0.1,Q0.1,DB2.100.2 ->/// Start address, such as M100.0,I0.1,Q0.1,DB2.100.2/// </param>/// <returns>包含结果对象的报文 -> Message containing the result object</returns>public static OperateResult<byte[]> BuildBitReadCommand(OperateResult<byte, int, ushort> analysis){//OperateResult<byte, int, ushort> analysis = AnalysisAddress(address);if (!analysis.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysis);byte[] _PLCCommand = new byte[31];_PLCCommand[0] = 0x03;_PLCCommand[1] = 0x00;// 长度 -> Length_PLCCommand[2] = (byte)(_PLCCommand.Length / 256);_PLCCommand[3] = (byte)(_PLCCommand.Length % 256);// 固定 -> Fixed_PLCCommand[4] = 0x02;_PLCCommand[5] = 0xF0;_PLCCommand[6] = 0x80;_PLCCommand[7] = 0x32;// 命令:发 -> command to send_PLCCommand[8] = 0x01;// 标识序列号_PLCCommand[9] = 0x00;_PLCCommand[10] = 0x00;_PLCCommand[11] = 0x00;_PLCCommand[12] = 0x01;// 命令数据总长度 -> Identification serial Number_PLCCommand[13] = (byte)((_PLCCommand.Length - 17) / 256);_PLCCommand[14] = (byte)((_PLCCommand.Length - 17) % 256);_PLCCommand[15] = 0x00;_PLCCommand[16] = 0x00;// 命令起始符 -> Command start character_PLCCommand[17] = 0x04;// 读取数据块个数 -> Number of data blocks read_PLCCommand[18] = 0x01;//===========================================================================================// 读取地址的前缀 -> Read the prefix of the address_PLCCommand[19] = 0x12;_PLCCommand[20] = 0x0A;_PLCCommand[21] = 0x10;// 读取的数据时位 -> Data read-time bit_PLCCommand[22] = 0x01;// 访问数据的个数 -> Number of Access data_PLCCommand[23] = 0x00;_PLCCommand[24] = 0x01;// DB块编号,如果访问的是DB块的话 -> DB block number, if you are accessing a DB block_PLCCommand[25] = (byte)(analysis.Content3 / 256);_PLCCommand[26] = (byte)(analysis.Content3 % 256);// 访问数据类型 -> Types of reading data_PLCCommand[27] = analysis.Content1;// 偏移位置 -> Offset position_PLCCommand[28] = (byte)(analysis.Content2 / 256 / 256 % 256);_PLCCommand[29] = (byte)(analysis.Content2 / 256 % 256);_PLCCommand[30] = (byte)(analysis.Content2 % 256);return OperateResult.CreateSuccessResult(_PLCCommand);}}
}
相关文章:
C#使用TCP-S7协议读写西门子PLC(三)
接上篇 C#使用TCP-S7协议读写西门子PLC(二)-CSDN博客 这里我们进行封装读写西门子PLC的S7协议命令以及连接西门子PLC并两次握手 新建部分类文件SiemensS7ProtocolUtil.ReadWrite.cs 主要方法: 连接西门子PLC并发送两次握手。两次握手成功后,才真正连…...

铝型材及其常用紧固件、连接件介绍
铝型材介绍(包括紧固件和连接件以及走线) 铝型材 铝型材一般是6063铝合金挤压成型,分为欧标和国标两个标准。(左边国标,右边欧标,欧标槽宽一点) 由于槽型不一样,相关的螺栓和螺母也…...
【裸机装机系列】7.kali(ubuntu)-安装开发所需工具
如果你是后端或是人工智能AI岗,可以安装以下推荐的软件: 1> sublime sublime官网 下载deb文件 安装命令 sudo dpkg -i sublime-text_build-4143_amd64.deb2> vscode 安装前置软件 sudo apt install curl gpg software-properties-common apt-t…...

[C语言]第九节 函数一基础知识到高级技巧的全景探索
目录 9.1 函数的概念 9.2 库函数 9.2.1 标准库与库函数 示例:常见库函数 9.2.2 标准库与头文件的关系 参考资料和学习工具 如何使用库函数 编辑 9.3 ⾃定义函数 9.3.1 函数的语法形式 9.3.2函数的举例 9.4 实参与形参 9.4.1 什么是实参? 9…...

1.1 计算机网络基本概述
欢迎大家订阅【计算机网络】学习专栏,开启你的计算机网络学习之旅! 文章目录 前言一、网络的基本概念二、集线器、交换机和路由器三、互连网与互联网四、网络的类型五、互连网的组成1. 边缘部分2. 核心部分 六、网络协议 前言 计算机网络是现代信息社会…...

Linux环境基础开发工具使用(gcc/g++与makefile)
1.Linux编译器-gcc/g使用 1. 背景知识 接下来的操作,我以gcc为例,因为两者选项都是通用的,所以也就相当于间接学习了 1.预处理(进行宏替换) 2.编译(生成汇编) 3.汇编(生成机器可识别代码)…...

PointNet++改进策略 :模块改进 | EdgeConv | DGCNN, 动态图卷积在3d任务上应用
目录 介绍核心思想及其实现核心思想实现步骤 如何改进PointNet**局部几何结构的处理****动态图的引入****特征聚合的灵活性****全局和局部特征的结合** 论文题目:Dynamic Graph CNN for Learning on Point Clouds发布期刊:TOG作者单位:麻省理…...
FFmpeg源码:skip_bits、skip_bits1、show_bits函数分析
GetBitContext结构体和其相关的函数分析: FFmpeg中位操作相关的源码:GetBitContext结构体,init_get_bits函数、get_bits1函数和get_bits函数分析 FFmpeg源码:skip_bits、skip_bits1、show_bits函数分析 一、skip_bits函数 skip…...

加密
一、加密 加密运算需要两个输入:密钥和明文 解密运算也需要两个输入:密钥和密文 密文通常看起来都是晦涩难懂、毫无逻辑的,所以我们一般会通过传输或者存储密文来保护私密数据,当然,这建立在一个基础上,…...

Kibana:如何使用魔法公式创建具有影响力的可视化效果?(第 1 部分)
作者:来自 Elastic Vincent du Sordet 我们将看到 Kibana Lens 编辑器中的神奇数学公式如何帮助突出显示高值。 简介 在上一篇博文《作为非设计师设计直观的 Kibana 仪表板》中,我们强调了创建直观仪表板的重要性。它展示了简单的更改(分组…...

【C++】多态and多态原理
目录 一、多态的概念 二、多态的定义及实现 🌟多态的构成条件 🌟虚函数 🌟虚函数的重写 🌠小贴士: 🌟C11 override 和 final 🌟重载、重写(覆盖)、重定义…...

C# 实现二维数据数组导出到 Excel
目录 功能需求 范例运行环境 Excel DCOM 配置 设计实现 组件库引入 编辑 方法设计 生成二维数据数组 核心方法实现 调用示例 总结 功能需求 将数据库查询出来的数据导出并生成 Excel 文件,是项目中经常使用的一项功能。本文将介绍通过数据集生成二维…...
nlohmann::json中有中文时调用dump转string抛出异常的问题
问题描述 Winodows下C开发想使用一个json库,使用的nlohmann::json,但是遇到json中使用中文时,转成string,会抛出异常。 nlohmann::json contentJson;contentJson["chinese"] "哈哈哈";std::string test con…...

Unity中InputField一些属性的理解
先看代码: using UnityEngine; using UnityEngine.UI;public class TestInput : MonoBehaviour {[SerializeField]InputField inputField;void Start(){Debug.Log(inputField.text);Debug.Log(inputField.text.Length);Debug.Log(inputField.preferredWidth);Debug…...

【webpack4系列】webpack构建速度和体积优化策略(五)
文章目录 速度分析:使用 speed-measure-webpack-plugin体积分析:使用webpack-bundle-analyzer使用高版本的 webpack 和 Node.js多进程/多实例构建资源并行解析可选方案使用 HappyPack 解析资源使用 thread-loader 解析资源 多进程并行压缩代码方法一&…...
从零开始搭建 PHP
🛠️ 从零开始搭建 PHP 环境:详细教程 PHP(Hypertext Preprocessor)是最流行的后端脚本语言之一,广泛用于构建动态网站和 Web 应用程序。在开始 PHP 开发之前,首先需要搭建 PHP 运行环境。无论你使用的是 …...

【数据结构】8——图3,十字链表,邻接多重表
数据结构8——图3,十字链表,邻接多重表 文章目录 数据结构8——图3,十字链表,邻接多重表前言一、十字链表结构例子 复杂例子 二、邻接多重表(Adjacency Multilist)例子 前言 除了之前的邻接矩阵和邻接表 …...
eth-trunk 笔记
LACP:Link Aggregation Control protocol 链路聚合控制协议 将多条以太网物理链路捆绑在一起成为一条逻辑链路,从而实现增加链路带宽的目的。同时,这些捆绑在一起的链路通过相互间的动态备份,可以有效地提高链路的可靠性 一、配…...

通信工程学习:什么是接入网(AN)中的TF传送功能
接入网(AN)中的TF传送功能 在通信工程中,TF(Transfer Function)传送功能是指为接入网(AN)不同位置之间提供通道和传输介质,以实现数据的有效传输。以下是关于TF传送功能的详细解释&a…...

【JavaEE】IO基础知识及代码演示
目录 一、File 1.1 观察get系列特点差异 1.2 创建文件 1.3.1 delete()删除文件 1.3.2 deleteOnExit()删除文件 1.4 mkdir 与 mkdirs的区别 1.5 文件重命名 二、文件内容的读写----数据流 1.1 InputStream 1.1.1 使用 read() 读取文件 1.2 OutputStream 1.3 代码演示…...

linux库(AI回答)
STL POSIX关系 DeepSeek-R1 回答完成 搜索全网22篇资料 STL(标准模板库)和 POSIX(可移植操作系统接口)是两种不同领域的技术标准,它们在 C/C 开发中各有侧重,但可以协同使用。以下是它们的关系和区别&…...

深度学习登上Nature子刊!特征选择创新思路
2025深度学习发论文&模型涨点之——特征选择 特征选择作为机器学习与数据挖掘领域的核心预处理步骤,其重要性在当今高维数据时代日益凸显。 通过识别最具判别性的特征子集,特征选择算法能够有效缓解"维度灾难"、提升模型泛化能力&#x…...

打卡第39天:Dataset 和 Dataloader类
知识点回顾: 1.Dataset类的__getitem__和__len__方法(本质是python的特殊方法) 2.Dataloader类 3.minist手写数据集的了解 作业:了解下cifar数据集,尝试获取其中一张图片 import torch import torch.nn as nn import…...

力扣面试150题--课程表
Day 63 题目描述 做法 初次思路:本质就是将所有前置课程和后置课程作为一个有向图(前者指向后者),判断这个图是否是一个有向无环图(即是否存在拓扑排序)(本质做法是dfs) 做法&…...

C++----剖析list
前面学习了vector和string,接下来剖析stl中的list,在数据库中学习过,list逻辑上是连续的,但是存储中是分散的,这是与vector这种数组类型不同的地方。所以list中的元素设置为一个结构体,将list设计成双向的&…...

大数据Spark(六十一):Spark基于Standalone提交任务流程
文章目录 Spark基于Standalone提交任务流程 一、Standalone-Client模式 1、提交命令 2、任务执行流程 二、Standalone-Cluster模式 1、提交命令 2、任务执行流程 Spark基于Standalone提交任务流程 在Standalone模式下,Spark的任务提交根据Driver程序运行的位…...
yaffs2目录搜索上下文数据结构struct yaffsfs_dirsearchcontext yaffsfs_dsc[] 详细解析
1. 目录搜索上下文(Directory Search Context) struct yaffsfs_dirsearchcontext 是 YAFFS2 文件系统中用于 目录遍历操作 的核心数据结构,专门管理 readdir() 等目录操作的状态。 结构体定义(典型实现) struct yaf…...

dvwa5——File Upload
LOW 在dvwa里建一个testd2.php文件,写入一句话木马,密码password antsword连接 直接上传testd2.php文件,上传成功 MEDIUM 查看源码,发现这一关只能提交jpg和png格式的文件 把testd2.php的后缀改成jpg,上传时用bp抓包…...
【学习记录】如何使用 Python 提取 PDF 文件中的内容
如何使用 Python 提取 PDF 文件中的内容 在文档自动化处理、数据提取和信息分析等任务中,从 PDF 文件中提取文本是一项常见需求。PDF 文件通常分为两种类型:基于文本的 PDF 和 包含扫描图像的 PDF。 本文将介绍如何使用 Python 分别提取这两种类型的 P…...

源码级拆解:如何搭建高并发「数字药店+医保购药」一体化平台?
在全民“掌上看病、线上购药”已成常态的今天,数字药店平台正在以惊人的速度扩张。而将数字药店与医保系统打通,实现线上医保购药,更是未来互联网医疗的关键拼图。 那么,如何从技术底层搭建一个 支持高并发、可扩展、安全合规的数…...