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

Andriod入门级开发

这学期有个课设,我们组我负责一个手机APP的开发,虽然刚开始说要实现什么智能导航,类似高德地图那种,但最后阉割的只剩一个Socket通信了,因为之前没有接触过(可能之后也不会再接触),记录一下开发中遇到的问题。

1.开发工具:Andriod Studio,主要功能:实现与开发板的Socket通信,具体是手机端收到板子消息按钮变色或者文本框显示对应文字,手机端也会发送消息给板子,让板子跳转用户操作界面,整个就是一个简单的前端,逻辑不需要手机端处理。手机端只负责显示。
2.实现效果:
在这里插入图片描述
在这里插入图片描述

3.一些关键问题和收获:
1)andriod studio 的使用:
感觉还是比较复杂的,前期的一些环境配置有点忘了,按照提示做就可以,主要是手机运行环境的一些配置,然后之后在打包程序安装在手机上出了点问题,需要密钥,按网上指导就可以。
对自带模板的灵活使用:as自带很多模板,比如我开发的这个丑陋的app就是在bottom Navigation Activity这个现成模板的基础上进行开发的。
在这里插入图片描述
之前as排版的Xml文件,下载手机上就会变乱。后面不知不觉就好了,注意这个问题。
2)Socket通信:
这个是这个项目的一个主要工作,其中遇到的第一个问题,怎么创建Socket通信:

class ConnectThread extends Thread {public void run() {try {//新建Socketsocket = new Socket("192.168.4.1", 8086);System.out.println("创建Socket成功");} catch (IOException e) {e.printStackTrace();}}}

Socket的收发信息:注意Socket的收发信息或者说对网络的操作不能直接在主线程进行,一般都需要开子线程。
Socket的收信息:

final byte[] buffer = new byte[1024];//创建接收缓冲区try {inputStream = socket.getInputStream();System.out.println("Socket接收数据成功");} catch (IOException e) {e.printStackTrace();}int len = 0;//数据读出来,并且返回数据的长try {len = inputStream.read(buffer);System.out.println("接收数据大小" + len);} catch (IOException e) {e.printStackTrace();}//BUFFER 内容转为字符串String recvStr = new String(buffer, 0, len);

Socket的发信息:

 //控制子线程开始public void buttonFunc() {// 在主线程中需要发送数据的代码片断前插入// 阻塞主线程,使子线程按照“同步”的方式执行try {System.out.println("线程开始");new Thread(sendthread).start();    // 线程启动new Thread(sendthread).join();     // 线程加入执行队列,主线程被阻塞,等待子线程执行完毕} catch (Exception e) {e.printStackTrace();System.out.println(e.toString());}}// 发送数据子线程final Runnable sendthread = new Runnable() {@Overridepublic void run() {try {System.out.println("发送数据的子线程执行中");try {try {//输出流初始化outputStream = socket.getOutputStream();System.out.println("outputStream创建成功");} catch (IOException e) {e.printStackTrace();}try {//写入数据outputStream.write(sendbuf);outputStream.flush();System.out.println("数据写入成功");} catch (IOException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}System.out.println("数据发送成功,子线程执行完毕");} catch (Exception e) {e.printStackTrace();System.out.println("子线程:"+ e.toString());}}};

socket的数据解析及数据格式:
收信息需要先转换为string类型,发信息如果要发16进制,byte数组直接写成16进制的形式。

源码:
美食城:

package com.example.parkingassitant2.ui.home;import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;import com.example.parkingassitant2.databinding.FragmentHomeBinding;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class HomeFragment extends Fragment {private FragmentHomeBinding binding;//发送数据保存byte[] sendbuf = {(byte) 0xaa, (byte) 0xaa,0x03, (byte) 0x12,0x03,0x18, (byte) 0xaa};Socket socket = null;        //定义socketOutputStream  outputStream = null;    //定义输出流(发送)public View onCreateView(@NonNull LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {HomeViewModel homeViewModel =new ViewModelProvider(this).get(HomeViewModel.class);binding = FragmentHomeBinding.inflate(inflater, container, false);View root = binding.getRoot();ConnectThread ct;ct = new ConnectThread();ct.start();//江底捞final Button jiangdilao = binding.xiaocaiyuan;//湖底捞按钮final Button hudilao = binding.A2;//河底捞按钮final Button hedilao = binding.B1;//海底捞按钮final Button haidilao = binding.B2;//KFC按钮final Button KFC = binding.C1;//小菜园按钮final Button xiaocaiyuan = binding.C2;//万达影城按钮final Button wanda = binding.D1;//星巴克按钮final Button starbuck = binding.D2;//江底捞按钮监听函数jiangdilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x12, 0x03, 0x18, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//湖底捞按钮监听函数hudilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x21, 0x03, 0x27, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//河底捞按钮监听函数hedilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x22, 0x03, 0x28, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//海底捞按钮监听函数haidilao.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x11, 0x03, 0x17, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//小菜园按钮监听函数xiaocaiyuan.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x13, 0x03, 0x19, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//星巴克按钮监听函数starbuck.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x14, 0x03, 0x1a, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//肯德基按钮监听函数KFC.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x23, 0x03, 0x29, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});//电影院按钮监听函数wanda.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同按钮对应不同的数据流sendbuf = new byte[]{(byte) 0xaa, (byte) 0xaa, 0x03, (byte) 0x24, 0x03, 0x2a, (byte) 0xaa};buttonFunc();Toast.makeText(getContext(), "预约成功,请更新停车场信息!", Toast.LENGTH_SHORT).show();}});return root;}class ConnectThread extends Thread {public void run() {try {//两个不同IP地址。网络助手和板子//socket = new Socket("192.168.71.1", 8086);//新建Socketsocket = new Socket("192.168.4.1", 8086);System.out.println("创建Socket成功");} catch (IOException e) {e.printStackTrace();}}}@SuppressLint("SuspiciousIndentation")@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;try {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}//控制子线程开始public void buttonFunc() {// 在主线程中需要发送数据的代码片断前插入// 阻塞主线程,使子线程按照“同步”的方式执行try {System.out.println("线程开始");new Thread(sendthread).start();    // 线程启动new Thread(sendthread).join();     // 线程加入执行队列,主线程被阻塞,等待子线程执行完毕} catch (Exception e) {e.printStackTrace();System.out.println(e.toString());}}// 发送数据子线程final Runnable sendthread = new Runnable() {@Overridepublic void run() {try {System.out.println("发送数据的子线程执行中");try {try {//输出流初始化outputStream = socket.getOutputStream();System.out.println("outputStream创建成功");} catch (IOException e) {e.printStackTrace();}try {//写入数据outputStream.write(sendbuf);outputStream.flush();System.out.println("数据写入成功");} catch (IOException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}System.out.println("数据发送成功,子线程执行完毕");} catch (Exception e) {e.printStackTrace();System.out.println("子线程:"+ e.toString());}}};
}

停车场:

package com.example.parkingassitant2.ui.dashboard;import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;import com.example.parkingassitant2.databinding.FragmentDashboardBinding;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class DashboardFragment extends Fragment {private FragmentDashboardBinding binding;Socket socket = null;		//定义socketOutputStream outputStream = null;    //定义输入流(接收)public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {DashboardViewModel dashboardViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);binding = FragmentDashboardBinding.inflate(inflater, container, false);View root = binding.getRoot();ConnectThread ct;ct = new ConnectThread();ct.start();return root;}class ConnectThread extends Thread{InputStream inputStream=null;	//定义输入流(接收)final Button A1 =binding.A1;final Button A2 = binding.A2;final Button D1 = binding.D1;public void run(){System.out.println(Thread.currentThread().getName()+": Hello");try {//socket = new Socket("192.168.71.1", 8086);socket = new Socket("192.168.4.1", 8086);binding.textView5.setText("连接成功");System.out.println("创建Socket成功");} catch (IOException e) {System.out.println("创建Socket失败");e.printStackTrace();}try{while (true){final byte[] buffer = new byte[1024];//创建接收缓冲区try {inputStream = socket.getInputStream();System.out.println("Socket接收数据成功");} catch (IOException e) {e.printStackTrace();}int len = 0;//数据读出来,并且返回数据的长try {len = inputStream.read(buffer);System.out.println("接收数据大小" + len);} catch (IOException e) {e.printStackTrace();}//BUFFER 内容转为字符串String recvStr = new String(buffer, 0, len);//找到读取开始处,一般为0int stadex = recvStr.indexOf("aaaa");System.out.println("解析数据开始位置" + stadex);int check_3,check_4,check_5,check_6;while(stadex < len){stadex = recvStr.indexOf("aaaa",stadex);int funcType_sta = stadex+4;int funcType_end = stadex+6;if(funcType_end > len || funcType_sta >= len){break;}//位置3是操作类型 02 是显示车牌预约停车场String pos3 = recvStr.substring(funcType_sta,funcType_end);// check_3 = Integer.parseInt(pos3);stadex = funcType_end;//停车预约功能中,位置4是车牌号String pos4 = recvStr.substring(stadex,stadex+2);//check_4 = Integer.parseInt(pos4);stadex += 2;//停车预约功能中,位置5是目的地String pos5 = recvStr.substring(stadex,stadex+2);//check_5 = Integer.parseInt(pos5);stadex += 2;String pos6 = recvStr.substring(stadex,stadex+2);//check_6 = Integer.parseInt(pos6);stadex += 2;//if( check_6 != check_3+check_4+check_5) break;stadex += 2;System.out.println("解析数据包" + "aaaa" + pos3 + pos4 + pos5 + pos6 + "aa");System.out.println("操作类型指示值:" + pos3);switch(pos3){case "01": {System.out.println("操作类型为欢迎车牌进站");String showText = null;switch (pos4) {case "01":showText = "欢迎京A00001";break;case "02":showText = "欢迎青ASB520";break;case "03":showText = "欢迎皖A66666";break;case "04":showText = "欢迎宁E88888";break;default:break;}binding.textView5.setText(showText);break;}case "04": {System.out.println("操作类型为停车预约");String showText = null;switch (pos4) {case "01":showText = "京A00001";break;case "02":showText = "青ASB520";break;case "03":showText = "皖A66666";break;case "04":showText = "宁E88888";break;default:break;}String address = null;switch (pos5){case "11":address = "海底捞";break;case "12":address = "江底捞";break;case "13":address = "小菜园";break;case "14":address = "星巴克";break;case "21":address = "湖底捞";break;case "22":address = "河底捞";break;case "23":address = "肯德基";break;case "24":address = "电影院";break;case "a1":address = "A1";break;case "a2":address = "A2";break;case "d1":address = "D1";break;default:break;}binding.textView5.setText(showText+"车主预约车位:" + address);break;}case "03": {System.out.println("操作类型为车位状态变更");switch (pos4) {case "a1": {if (pos5.equals("00")) {binding.A1.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.A1.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.A1.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}case "a2": {System.out.println("pos5: ");System.out.println(pos5);if (pos5.equals("00")) {binding.A2.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.A2.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.A2.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}case "d1": {if (pos5.equals("00")) {binding.D1.setBackgroundColor(Color.parseColor("#00FF00"));} else if (pos5.equals("01")) {binding.D1.setBackgroundColor(Color.parseColor("#FF0000"));} else if (pos5.equals("02")) {binding.D1.setBackgroundColor(Color.parseColor("#FFFF00"));}break;}default:break;}}default:break;}}}} catch (Exception ex) {ex.printStackTrace();}}}@SuppressLint("SuspiciousIndentation")@Overridepublic void onDestroyView() {super.onDestroyView();try {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}binding = null;}
}

相关文章:

Andriod入门级开发

这学期有个课设&#xff0c;我们组我负责一个手机APP的开发&#xff0c;虽然刚开始说要实现什么智能导航&#xff0c;类似高德地图那种&#xff0c;但最后阉割的只剩一个Socket通信了&#xff0c;因为之前没有接触过&#xff08;可能之后也不会再接触&#xff09;&#xff0c;记…...

DCL 数据控制语言

1、简介 DCL英文全称是Data Control Language(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 2、管理用户 2.1 查询用户 select * from mysql.user;查询的结果如下: 其中 Host代表当前用户访问的主机, 如果为localhost, 仅代表只能够在当前本机访问…...

全网超详细的下载与安装VMware虚拟机以及为什么要安装VMware虚拟机

文章目录1. 文章引言2. 下载VMware3. 安装VMware1. 文章引言 我们使用最多的系统是windows系统&#xff0c;因为&#xff0c;国内电脑厂商的操作系统(os)基本是windows系统&#xff0c;比如华为、联想、华硕等电脑。 但线上的服务器大多是Linux系统&#xff0c;而我们经常使用…...

Python获取zabbix问题触发器

背景&#xff1a;阿里云的ECS服务器因为阿里云升级插件&#xff0c;导致安全防护程序重启&#xff0c;产生不同的端口。导致低自动发现注册的端口 大量报警。 解决&#xff1a;杀掉关于因为非业务 变更的端口检测的触发器。 相关文档&#xff1a; Zabbix监控之主机端口监控自…...

原型链污染

目录 前置知识 原型对象 prototype和__proto__的区别 原型链概念 原型链的继承 原型 链污染 原型链污染原理 javascript中可能会存在原型链污染的危险函数 原型链污染的实际应用 JavaScript中可以触发弹窗的函数 前置知识 原型对象 在JavaScript中&#xff0c;每个函…...

ClickHouse详解

一、概念ClickHouse是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。OLAP场景的关键特征绝大多数是读请求数据以相当大的批次(> 1000行)更新&#xff0c;而不是单行更新;或者根本没有更新。已添加到数据库的数据不能修改。对于读取&#xff0c;从数据库中提取相当多的…...

02_Docker 安装

02_Docker 安装 文章目录02_Docker 安装2.1 安装 Docker 的先决条件2.2 在 Ubuntu 和 Debain 中安装 Docker2.2.1 检查前提条件1. 内核2.检查 Device Manager2.2 安装 DockerDocker 支持非常多的Linux平台&#xff0c;包括Ubuntu和RHEL&#xff0c;除此之外&#xff0c;Docker还…...

K8S集群将Docker切换到Containerd

文章目录1. 开启节点维护1.1 将节点设置成不可调度1.2 驱逐节点上的 Pod1.3 停止相关服务2. 升级到 containerd2.1 安装 containerd2.2 调整 containerd 配置2.3 修改 kubelet 启动配置参数3. 重启节点服务4. 验证升级后的节点5. 容器管理工具5.1 容器管理命令行工具对比5.2 cr…...

Kubernetes03:kubernetes 功能和架构

2.1 概述 Kubernetes 是一个轻便的和可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过 Kubernetes 能够进行应用的自动化部署和扩缩容。在 Kubernetes 中&#xff0c;会将组成应用的容 器组合成一个逻辑单元以更易管理和发现。Kubernetes 积累了作为 Google 生产环…...

LabVIEW中CPU和内存使用情况在NI分布式系统管理器中不可见

LabVIEW中CPU和内存使用情况在NI分布式系统管理器中不可见想使用NI分布式系统管理器监测网络连接实时控制器的CPU和内存使用情况。从左侧窗口的树中选择了感兴趣的实时目标&#xff0c;然后通过选择视图自动视图来确保启用自动查看。希望看到CPU/内存选项卡&#xff0c;但它有显…...

buu [NPUCTF2020]Classical Cipher 1

题目描述&#xff1a; 题目分析&#xff1a; 首先输入密码 {gsv_pvb_rh_zgyzhs} 后&#xff0c;得到&#xff1a;可以得知密码是错误的&#xff0c;再看看密码 {gsv_pvb_rh_zgyzhs} &#xff0c;排列无序&#xff0c;那么尝试用凯撒与栅栏解密&#xff0c;发现还是解不出&…...

分享96个HTML体育竞技模板,总有一款适合您

分享96个HTML体育竞技模板&#xff0c;总有一款适合您 96个HTML体育竞技模板下载链接&#xff1a;https://pan.baidu.com/s/1k2vJUlbd2Boduuqqa0EWMA?pwdj8ji 提取码&#xff1a;j8ji Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 北京奥运火炬PSD模板 奥运…...

Python pandas「原有或者新建」Excel中「追加新或者新建」sheet

1.pandas原有Excel中追加新sheet 使用Pandas库&#xff0c;我们可以轻松将数据追加到现有的Excel工作簿中的新工作表中。以下是追加新工作表的简单步骤&#xff1a; 读取现有的Excel文件 使用Pandas库中的read_excel()函数读取现有的Excel文件。指定Excel文件的路径和文件名&a…...

程序员必备的软技能- CPU“没有灵魂的躯体”

引言 先引用一段比较有意思的论述&#xff1a; 现实中每个人是由两部分构成&#xff0c;灵魂和躯体&#xff0c;灵魂依附于躯体游走于世间&#xff0c;现实中我们面对的每个人其实面对的是其灵魂而非肉体&#xff0c;肉体不过是表象而已。 灵魂本性乃一恶物&#xff0c;寄生于…...

基于微信小程序的青少年生理健康知识小助手

基于微信小程序的青少年生理健康知识小助手 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目…...

【scl】博图程序的导入和导出

导入或者导出博图文件的方法&#xff08;也叫移植文件&#xff09; 目录 前言 ​编辑 ​编辑 前言 本篇文章主要写一下关于博图文件的导入和导出&#xff0c;具体要怎么样才能将写好的程序或者块移植到其他地方&#xff0c;下面我们一起来看&#xff01; 一、程序块的导入和导…...

【C语言】指针进阶

目录 一、字符指针 二、指针数组 三、数组指针 四、数组指针的使用 五、函数指针数组 六、指向函数指针数组的指针 七、回调函数 我们知道了指针的概念&#xff1a; 1. 指针就是个变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间。 2. 指针的大小是…...

18:CTK 总结篇(FAQ)

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 经过了几个月的艰苦奋战,终于到了最后一节啦,是不是和我一样,心里有点儿小激动! 回顾之前的章节,从初级 -> 进阶 -> 高级,我们针对 CTK 做了详细的分类讲解。希望通过这些知识,大家能对模块化…...

概论_第7章_参数估计_真题__求置信区间

真题 2014.10 第30题 测量某物体的质量9次&#xff0c; 测得平均值 x‾15.4\overline x 15.4x15.4 g, 已知测量数据 XXX ~ N(μ,0.09)N(\mu, 0.09)N(μ,0.09) (1) 求该物体质量的置信度为0.95 的置信区间&#xff1b; &#xff08;2&#xff09;为了使置信度为0.95 的置信区间…...

Go 1.21的2个语言变化

语言行为变化 Go 1.20已经于今年2月份发布&#xff0c;Go 1.21也不远了&#xff0c;我们来先堵为快&#xff0c;看看Go 1.21版本里几个有趣的变化。 文末附送2道面试题。 panic(nil) func main() {defer func() {print(recover() nil)}()panic(nil) }大家先想一想这段代码…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...