Java 串口通信—收发,监听数据(代码实现)
一、串口通信与串行通信的原理


串行通信是指仅用一根接收线和一根发送线,将数据以位进行依次传输的一种通讯方式,每一位数据占据一个固定的时间长度。
串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。
串口通信时首先要约定好帧格式与波特率,并且串口通信采用TTL逻辑(Transistor-Transistor Logic) 是指晶体管-晶体管逻辑。

TTL逻辑门的标准输出状态是:
高电平(逻辑“1”或HIGH):典型值为+2.4V至+5V(对于标准5V电源供电的TTL),代表有效信号。
低电平(逻辑“0”或LOW):典型值接近于地电压(0V至+0.4V),代表无效信号。
这种通信方式抗干扰能力弱,下图中,静电让某一个低电平变高,就会导致通信距离很短,越1米。

所以为了提示通信的稳定性与距离,产生了由美国制订的推荐标准RS232、RS485,都是在基础串口通信的基础上加了特定的电平转换芯片改变电压传输值。
串口通信主要可分为232、485、422三种通信方式。
232通信

232通信主要是由RX、TX、GND三根线组成。RX接TX,TX接RX,GND接GND。发送和接收由不同的线路处理,所以能够同时进行发送和接收数据,因此232是全双工通信。
485通信

为了解决232通信距离受限问题,于是有了485通信。 485通信只需要+、-两根线(也叫A、B两根线),A、B两根线的差分电平信号就是作为数据信号传输。发送和接收都用这两根线,每次只能发送数据或者接收数据,因此485是半双工通信。
422通信

422通信兼具232与485的特点,既能实现全双工通信,又能增大传输距离。422也常被标注为485-4,而485被标注为485-2。因为485-2是2根线,485-4是4根线。


并行和串行的区别:
-
并行传输: 多根线路传输,每条物理线代表一个比特位,可以同时发送和接受多个字节;
-
串行传输: 只用一条线路传输,逐位传输,字节内允许出现延迟(如开始或结束等),而每个字节之间必须有完整的停止和起始位置。
同步传输和异步传输的差别:
-
同步传输:在知道对方状态下进行全双工传输,需要调节系统时钟,使得传送速度不超过缓存容量,并保持包络上均衡。
-
异步传输:既能针对字符流,也可针对比特流。异步传输没有明确定义的“帧”模式,因此不需要同步时钟,但会增加一个帧同步域,用于在接收端恢复字节边界,并通过位数逐个地进行帧的识别。
在实际应用中,串口通常使用异步技术来发送和接收数据。异步传输可以按需动态调整数据传输速率,以便快速响应用户操作或自动控制事件的发生。
二、Java 实现串口通信
准备工作
要想使用串口包进行串口通信,除了设置好环境变量之外,还要准备对应的串口通信的jar包
1. 下载对应版本的rxtx 解压后得到三个文件 rxtxParallel.dll、rxtxSerial.dll、RXTXcomm.jar/
下载地址如下:RXTX for Java (fizzed.com)

2. 将rxtxParallel.dll、rxtxSerial.dll 放进当前使用的jdk的bin目录( jdk版本必须与下载的rxtx一致 ,区分32位/64位 AMD/IA)

3. (windows x64系统可以将当前项目libs下的 rxtxParallel.dll、rxtxSerial.dll 直接放入jdk下的bin目录)
4. 需要将libs下的RXTXcomm.jar加入项目依赖,将javax.usb.properties复制到 JRE\lib或者JDK\lib.
<dependency><groupId>org.rxtx</groupId><artifactId>rxtx</artifactId><version>2.2</version><scope>system</scope><systemPath>${project.basedir}/src/main/resources/lib/RXTXcomm.jar</systemPath>
</dependency>
说明:(如果没有正常引入将会出现这个错误)

代码实现
package com.ss.serialport.controller;import gnu.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;public class SerialPortTool {public static void main(String[] args) {// 查询串口findSystemAllComPort();// //发送16进制数据——实际应用中串口通信传输的数据,大都是 16 进制String hexStrCode = "455A432F5600";SerialPort serialPort = SerialPortTool.openComPort(null, 38400, 8, 1, 0);// 设置串口监听SerialPortTool.setListenerToSerialPort(serialPort, new SerialPortEventListener() {@Overridepublic void serialEvent(SerialPortEvent arg0) {if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {//数据通知byte[] bytes = SerialPortTool.readData(serialPort);System.out.println("收到的数据长度:" + bytes.length);System.out.println("收到的数据:" + new String(bytes));}}});new Thread(new Runnable() {@Overridepublic void run() {int i = 1;while (i < 1000) {byte[] bytes = hexStrCode.getBytes();SerialPortTool.sendDataToComPort(serialPort, bytes);//发送数据i++;try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}/*** 查找电脑上所有可用 com 端口** @return 可用端口名称列表,没有时 列表为空*/public static final ArrayList<String> findSystemAllComPort() {/*** getPortIdentifiers:获得电脑主板当前所有可用串口*/Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();ArrayList<String> portNameList = new ArrayList<>();/*** 将可用串口名添加到 List 列表*/System.out.println("===========串口信息start==============");while (portList.hasMoreElements()) {CommPortIdentifier commPortIdentifier = portList.nextElement();StringBuffer returnStr = new StringBuffer();String portName = commPortIdentifier.getName();//名称如 COM1、COM2....String isOwner = String.valueOf(commPortIdentifier.isCurrentlyOwned());returnStr.append(isOwner).append("\t 占用情况:").append(isOwner);System.out.println(returnStr);portNameList.add(portName);}System.out.println("===========串口信息end==============");return portNameList;}/*** 打开电脑上指定的串口** @param portName 端口名称,如 COM1,为 null 时,默认使用电脑中能用的端口中的第一个* @param b 波特率(baudrate),如 9600* @param d 数据位(datebits),如 SerialPort.DATABITS_8 = 8* @param s 停止位(stopbits),如 SerialPort.STOPBITS_1 = 1* @param p 校验位 (parity),如 SerialPort.PARITY_NONE = 0* @return 打开的串口对象,打开失败时,返回 null*/public static final SerialPort openComPort(String portName, int b, int d, int s, int p) {CommPort commPort = null;try {//当没有传入可用的 com 口时,默认使用电脑中可用的 com 口中的第一个if (portName == null || "".equals(portName)) {List<String> comPortList = findSystemAllComPort();if (comPortList != null && comPortList.size() > 0) {portName = comPortList.get(0);}}System.out.println("开始打开串口:portName=" + portName + ",baudrate=" + b + ",datebits=" + d + ",stopbits=" + s + ",parity=" + p);//通过端口名称识别指定 COM 端口CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);/*** open(String TheOwner, int i):打开端口* TheOwner 自定义一个端口名称,随便自定义即可* i:打开的端口的超时时间,单位毫秒,超时则抛出异常:PortInUseException if in use.* 如果此时串口已经被占用,则抛出异常:gnu.io.PortInUseException: Unknown Application*/commPort = portIdentifier.open(portName, 5000);/*** 判断端口是不是串口* public abstract class SerialPort extends CommPort*/if (commPort instanceof SerialPort) {SerialPort serialPort = (SerialPort) commPort;/*** 设置串口参数:setSerialPortParams( int b, int d, int s, int p )* b:波特率(baudrate)* d:数据位(datebits),SerialPort 支持 5,6,7,8* s:停止位(stopbits),SerialPort 支持 1,2,3* p:校验位 (parity),SerialPort 支持 0,1,2,3,4* 如果参数设置错误,则抛出异常:gnu.io.UnsupportedCommOperationException: Invalid Parameter* 此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用*/serialPort.setSerialPortParams(b, d, s, p);System.out.println("打开串口 " + portName + " 成功...");return serialPort;} else {System.out.println("当前端口 " + commPort.getName() + " 不是串口...");}} catch (NoSuchPortException e) {e.printStackTrace();} catch (PortInUseException e) {System.out.println("串口 " + portName + " 已经被占用,请先解除占用...");e.printStackTrace();} catch (UnsupportedCommOperationException e) {System.out.println("串口参数设置错误,关闭串口,数据位[5-8]、停止位[1-3]、验证位[0-4]...");e.printStackTrace();if (commPort != null) {//此时必须关闭串口,否则下次 portIdentifier.open 时会打不开串口,因为已经被占用commPort.close();}}System.out.println("打开串口 " + portName + " 失败...");return null;}/*** 往串口发送数据** @param serialPort 串口对象* @param orders 待发送数据*/public static void sendDataToComPort(SerialPort serialPort, byte[] orders) {OutputStream outputStream = null;try {if (serialPort != null) {outputStream = serialPort.getOutputStream();outputStream.write(orders);outputStream.flush();System.out.println("往串口 " + serialPort.getName() + " 发送数据:" + Arrays.toString(orders) + " 完成...");} else {System.out.println("gnu.io.SerialPort 为null,取消数据发送...");}} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}}}/*** 从串口读取数据** @param serialPort 要读取的串口* @return 读取的数据*/public static byte[] readData(SerialPort serialPort) {InputStream is = null;byte[] bytes = null;try {is = serialPort.getInputStream();//获得串口的输入流int bufflenth = is.available();//获得数据长度while (bufflenth != 0) {bytes = new byte[bufflenth];//初始化byte数组is.read(bytes);bufflenth = is.available();}} catch (IOException e) {e.printStackTrace();} finally {try {if (is != null) {is.close();is = null;}} catch (IOException e) {e.printStackTrace();}}return bytes;}/*** 给串口设置监听** @param serialPort* @param listener*/public static void setListenerToSerialPort(SerialPort serialPort, SerialPortEventListener listener) {try {//给串口添加事件监听serialPort.addEventListener(listener);} catch (TooManyListenersException e) {e.printStackTrace();}serialPort.notifyOnDataAvailable(true);//串口有数据监听serialPort.notifyOnBreakInterrupt(true);//中断事件监听}/*** 关闭串口** @param serialPort 待关闭的串口对象*/public static void closeComPort(SerialPort serialPort) {if (serialPort != null) {serialPort.close();System.out.println("关闭串口 " + serialPort.getName());}}/*** 16进制字符串转十进制字节数组* 这是常用的方法,如某些硬件的通信指令就是提供的16进制字符串,发送时需要转为字节数组再进行发送** @param strSource 16进制字符串,如 "455A432F5600",每两位对应字节数组中的一个10进制元素* 默认会去除参数字符串中的空格,所以参数 "45 5A 43 2F 56 00" 也是可以的* @return 十进制字节数组, 如 [69, 90, 67, 47, 86, 0]*/public static byte[] hexString2Bytes(String strSource) {if (strSource == null || "".equals(strSource.trim())) {System.out.println("hexString2Bytes 参数为空,放弃转换.");return null;}strSource = strSource.replace(" ", "");int l = strSource.length() / 2;byte[] ret = new byte[l];for (int i = 0; i < l; i++) {ret[i] = Integer.valueOf(strSource.substring(i * 2, i * 2 + 2), 16).byteValue();}return ret;}}
整合成串口工具类 :
package com.ss.serialport.utils;import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;/*** @ClassName DLSC_SerialPort* @Description 串口工具类 :打开串口 ;接受数据 ;发送数据* @Version 1.0*/
public class DLSC_SerialPort {private SerialPort serialPort;private InputStream inputStream;private OutputStream outputStream;private BlockingQueue<String> receivedDataQueue = new LinkedBlockingQueue<>();private volatile boolean isRunning = true;private void connect(String portName) throws Exception {// 获取串口通信端口实例CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portName);if (portId.isCurrentlyOwned()) {System.err.println("Error: Port is currently in use");} else {// 打开端口,并获取输入、输出流serialPort = (SerialPort) portId.open("SerialCommExample", 2000);inputStream = serialPort.getInputStream();outputStream = serialPort.getOutputStream();// 设置串口参数serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);// 启动读取数据的线程Thread readThread = new Thread(() -> {try {while (isRunning) {int available = inputStream.available();if (available > 0) {byte[] bytes = new byte[available];inputStream.read(bytes);String data = new String(bytes, "UTF-8");receivedDataQueue.put(data); // 将数据放入队列}Thread.sleep(100); // 等待一段时间再检查是否有新数据}} catch (IOException | InterruptedException e) {e.printStackTrace();}});readThread.start();}}private void sendData(String data) throws IOException {if (outputStream != null) {outputStream.write(data.getBytes("UTF-8"));outputStream.flush(); // 确保数据被发送出去}}private String receiveData(long timeout) throws InterruptedException {return receivedDataQueue.poll(timeout, TimeUnit.MILLISECONDS); // 尝试从队列中获取数据,超时则返回null}private void disconnect() throws Exception {isRunning = false; // 设置标志位以停止读取数据的线程if (serialPort != null) {serialPort.removeEventListener();serialPort.close();}}public static void send (String msg) {DLSC_SerialPort example = new DLSC_SerialPort();try {// 连接到串口example.connect("COM3"); // 替换为你的串口名称// 发送数据example.sendData(msg + "\r\n");// 断开连接example.disconnect();} catch (Exception e) {e.printStackTrace();}}public static Double sendAndReceives(String msg) {DLSC_SerialPort example = new DLSC_SerialPort();try {// 连接到串口example.connect("COM1"); // 替换为你的串口名称// 发送数据example.sendData(msg + "\r\n");// 等待并接收数据String receivedData = example.receiveData(5000); // 等待最多5秒来获取数据if (receivedData != null) {Double backData = Double.valueOf(receivedData);System.out.println("Received data: " + backData);return backData;} else {System.out.println("No data received within the timeout period.");}// 断开连接example.disconnect();} catch (Exception e) {e.printStackTrace();}return null;}// public static String sendAndReceive(String msg) {
//
// SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
// ArrayList<String> port = serialPortUtil.findPort();
// if (port != null && !port.isEmpty()) {
// System.out.println("没有发现任何端口");
// }
// String portName = port.get(2);
// SerialPort serialPort = serialPortUtil.openPort(
// portName, 9600, 8, 1, 0);
// if (serialPort == null) {
// System.out.println("打开串口(" + portName + ")失败");
// }
// System.out.println("成功连接串口:" + portName);serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());
// byte[] bytes = serialPortUtil.readFromPort(serialPort);
// if (bytes != null) {
// return new String(bytes);
// }
// serialPortUtil.closePort(serialPort);
// return null;
// }// public static String sendAndReceive(String msg) {
//
// SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();
// ArrayList<String> port = serialPortUtil.findPort();
// if (port != null && !port.isEmpty()) {
// System.out.println("没有发现任何端口");
// }
// String portName = port.get(0);
// SerialPort serialPort = serialPortUtil.openPort(
// portName, 9600, 8, 1, 0);
// if (serialPort == null) {
// System.out.println("打开串口(" + portName + ")失败");
// }
// System.out.println("成功连接串口:" + portName);serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());
// try {
// Thread.sleep(6000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());
// byte[] bytes = serialPortUtil.readFromPort(serialPort);
// if (bytes != null) {
// return new String(bytes);
// }
// System.out.println(serialPort);
// serialPortUtil.closePort(serialPort);
// return null;
// }public static String sendAndReceive(String msg) {SerialPortUtil serialPortUtil = SerialPortUtil.getSerialPortUtil();ArrayList<String> port = serialPortUtil.findPort();System.out.println(port);if (port == null || port.isEmpty()) {System.out.println("没有发现任何端口");return null;}String portName = port.get(0);SerialPort serialPort = serialPortUtil.openPort(portName, 9600, 8, 1, 0);if (serialPort == null) {System.out.println("打开串口(" + portName + ")失败");return null;}System.out.println("成功连接串口:" + portName);try {// serialPortUtil.sendToPort(serialPort, "SOUR:VOLT 28\r\n".getBytes());Thread.sleep(6000);serialPortUtil.sendToPort(serialPort, "SOUR:CURR:LIMIT:HIGH?\r\n".getBytes());byte[] bytes = serialPortUtil.readFromPort(serialPort);if (bytes != null) {return new String(bytes);} else {System.out.println("未读取到任何数据");return null;}} catch (InterruptedException e) {e.printStackTrace();return null;} finally {// 确保串口在所有情况下都关闭serialPortUtil.closePort(serialPort);}}
}

相关文章:
Java 串口通信—收发,监听数据(代码实现)
一、串口通信与串行通信的原理 串行通信是指仅用一根接收线和一根发送线,将数据以位进行依次传输的一种通讯方式,每一位数据占据一个固定的时间长度。 串口通信(Serial Communications)的概念非常简单,串口按位&#x…...
fileinput pdf编辑初始化预览
var $fileLinkInput $(#file_link_full); $fileLinkInput.fileinput({language: zh,uploadUrl: <?php echo Yii::$app->urlManager->createUrl([file/image, type > work_file]);?>,initialPreview: [defaultFile],initialPreviewAsData: true,initialPrevie…...
微信支付开发-需求整理及需求设计
一、客户要求 1、通过唤醒机器人参与答题项,机器人自动获取题目,用户进行答题; 2、用户答对题数与后台设置的一样或者更多,则提醒用户可以领取奖品,但是需要用户支付邮费; 3、用户在几天之内不能重复领取奖…...
vs code: pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本
在visual studio code运行pnpm出错: pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本 解决方案: 到C:\Program Files\nodejs文件夹下删除pnpm.ps1即可。 C:\Program Files\nodejs改成你自己的路径...
web测试必备技能:浏览器兼容性测试
如今,市面上的浏览器种类越来越多(尤其是在平板和移动设备上),这就意味着你所测试的站点需要在这些你声称支持浏览器上都能很好的工作。 同时,主流浏览器(IE,Firefox,Chrome&#x…...
《数据资产管理核心技术与应用》首次大型赠书活动圆满结束
《数据资产管理核心技术与应用》是清华大学出版社出版的一本图书,作者为张永清等著,在2024.9.11号晚上20:00,本书作者张永清联合锋哥聊数仓公众号和清华大学出版社一起,向各大大数据技术爱好者通过三轮互动活动赠送了3本正版图书。…...
vue在一个组件引用其他组件
在vue一个组件中引用另一个组件的步骤 必须在script中导入要引用的组件需要在export default的components引用导入的组件(这一步经常忘记)在template使用导入的组件<script><!-- 第一步,导入--> import Vue01 from "@/components/Vue01.vue";...
软件测试学习笔记丨Postman实战练习
本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/32096#h-22 二、实战练习 2.1 宠物商店接口文档分析 接口文档:http://petstore.swagger.io ,这是宠物商店接口的 swagger 文档。 2.1.1 什么是 swagger Swagger 是…...
kubernetes微服务基础及类型
目录 1 什么是微服务 2 微服务的类型 3 ipvs模式 ipvs模式配置方式 4 微服务类型详解 4.1 ClusterIP 4.2 ClusterIP中的特殊模式headless 4.3 nodeport 4.4 metalLB配合loadbalance实现发布IP 1 什么是微服务 用控制器来完成集群的工作负载,那么应用如何暴漏出去&…...
linux-L3_linux 查看进程(node-red)
linux 查看进程 以查看进程node-red为例 ps aux | grep node-red...
区块链之变:揭秘Web3对互联网的改变
传统游戏中,玩家的虚拟资产(如角色、装备)通常由游戏公司控制,玩家无法真正拥有这些资产或进行交易。而在区块链游戏中,虚拟资产通过去中心化技术记录在区块链上,玩家对其拥有完全的所有权,并能…...
SAP B1 Web Client MS Teams App集成连载一:先决条件/Prerequisites
一、先决条件/Prerequisites 在设置 SAP Business One 应用之前,确保您已具备以下各项:Before you set up the SAP Business One app, make sure you have acquired the following: 1.Microsoft Teams 管理员账户/A Microsoft Teams admin account 您需…...
去除单细胞数据中环境游离的RNA污染-decontX工具学习
DecontX 是一种用于单细胞 RNA 测序数据的去除环境污染物(decontamination)的工具,主要用于减少由细胞外RNA造成的污染效应。 开发者在20年的文章中已经把这个工具适用的情况说的非常清楚了:简单来说就是基于微流控的单细胞技术会…...
Games101图形学笔记——光栅化
这里写目录标题 Rasterization光栅化屏幕空间隔行扫描三角形采样采样产生的问题反走样处理方法:采样前模糊 频率,时域傅里叶级数展开傅里叶变换 滤波高通滤波低通滤波 卷积卷积的一些定理 反走样MSAA(Multisample Anti-Aliasing)多…...
2024年汉字小达人区级自由报名的几个最新问题和真题练一练
2024年第十一届汉字小达人的区级活动的时间9月25-30日正式开赛,还有不到两周。 今天继续回答家长和孩子们的几个问题,并给大家看看一些真题,让孩子对汉字小达人的题型和比赛有直观的了解,从而更好地备考。 本专题在比赛前持续更…...
从简单分析到智能问数,Smartbi AIChat让数据回归业务
大数据产业创新服务媒体 ——聚焦数据 改变商业 在某科技公司,资深数据分析师李晨(化名)正忙于分析新产品的市场表现。面对传统自助式BI工具,李晨在功能界面中手动设置各种查询条件,进行了一番复杂的拖拉拽操作&#…...
基于SpringBoot+Vue+MySQL的考编论坛网站
系统展示 用户前台界面 管理员后台界面 系统背景 在当前信息化高速发展的时代,考编已成为众多求职者的重要选择。然而,备考过程中信息获取、经验交流及资源分享的需求日益凸显。基于SpringBoot、Vue.js与MySQL构建的考编论坛网站应运而生,旨在…...
SpringSecurity剖析
1、SpringSecurity 入门 1.1、简介 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Sp…...
一文搞懂 Flink Graph 构建过程源码
一文搞懂 Flink Graph 构建过程 1. StreamGraph构建过程1.1 transform(): 构建的核心1.2 transformOneInputTransform1.3 构造顶点1.4 构造边1.5 transformSource1.6 transformPartition1.7 transformSink 1. StreamGraph构建过程 链接: 一文搞懂 Flink 其他重要源码点击我 e…...
【spring】IDEA 新建一个spring boot 项目
参考新建项目-sprintboot 选择版本、依赖,我选了一堆 maven会重新下载一次么?...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
