【跟小嘉学 Rust 编程】二十一、网络编程
系列文章目录
【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
【跟小嘉学 Rust 编程】十一、编写自动化测试
【跟小嘉学 Rust 编程】十二、构建一个命令行程序
【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包
【跟小嘉学 Rust 编程】十四、关于 Cargo 和 Crates.io
【跟小嘉学 Rust 编程】十五、智能指针(Smart Point)
【跟小嘉学 Rust 编程】十六、无畏并发(Fearless Concurrency)
【跟小嘉学 Rust 编程】十七、面向对象语言特性
【跟小嘉学 Rust 编程】十八、模式匹配(Patterns and Matching)
【跟小嘉学 Rust 编程】十九、高级特性
【跟小嘉学 Rust 编程】二十、进阶扩展
【跟小嘉学 Rust 编程】二十一、网络编程
文章目录
- 系列文章目录
- @[TOC](文章目录)
- 前言
- 一、 TCP
- 1.1、std::net::TcpListener
- 1.1.1、bind
- 1.1.2、try_clone 方法
- 1.1.3、accept 方法
- 1.1.4、incoming 方法
- 1.1.5、into_incoming 方法
- 1.1.6、ttl 相关方法
- 1.1.7、set_nonblocking
- 1.2、地址相关类
- 1.2.1、Ipv4Addr/IpV6Addr/IpAddr
- 1.2.2、SocketAddr/SocketAddrV4/SocketAddrV6
- 1.3、std::net::TCPStream
- 1.3.1、connect 方法连接服务器
- 1.3.2、connect_timeout
- 1.3.3、shutdown
- 1.3.4、try_clone
- 1.3.5、set_read_timeout 和 set_write_timeout
- 1.3.6、peek
- 1.3.7、set_linger
- 1.3.8、set_nodelay
- 二、 std::net::UdpSocket
- 2.1.1、bind 方法
- 2.1.2、recv_from 方法
- 2.1.3、peek_from 方法
- 2.1.4、send_to 方法
- 2.1.5、try_clone 方法
- 2.1.6、set_read_timeout 和 set_write_timeout
- 2.1.7、UDP 广播
- 2.1.7.2、广播
- 2.1.7.1、set_broadcast
- 2.1.8、UDP 组播
- 2.1.8.1、组播
- 2.1.8.2、set_multicast_loop_v4 和 set_multicast_loop_v6
- 2.1.8.3、set_multicast_ttl_v4 和 set_multicast_ttl_v6
- 2.1.8.4、leave_multicast_v4 和 leave_multicast_v6
- 2.1.8.5、join_multicast_v4 和 join_multicast_v6
- 2.1.9、set_ttl
- 2.1.10、set_nonblocking
- 总结
文章目录
- 系列文章目录
- @[TOC](文章目录)
- 前言
- 一、 TCP
- 1.1、std::net::TcpListener
- 1.1.1、bind
- 1.1.2、try_clone 方法
- 1.1.3、accept 方法
- 1.1.4、incoming 方法
- 1.1.5、into_incoming 方法
- 1.1.6、ttl 相关方法
- 1.1.7、set_nonblocking
- 1.2、地址相关类
- 1.2.1、Ipv4Addr/IpV6Addr/IpAddr
- 1.2.2、SocketAddr/SocketAddrV4/SocketAddrV6
- 1.3、std::net::TCPStream
- 1.3.1、connect 方法连接服务器
- 1.3.2、connect_timeout
- 1.3.3、shutdown
- 1.3.4、try_clone
- 1.3.5、set_read_timeout 和 set_write_timeout
- 1.3.6、peek
- 1.3.7、set_linger
- 1.3.8、set_nodelay
- 二、 std::net::UdpSocket
- 2.1.1、bind 方法
- 2.1.2、recv_from 方法
- 2.1.3、peek_from 方法
- 2.1.4、send_to 方法
- 2.1.5、try_clone 方法
- 2.1.6、set_read_timeout 和 set_write_timeout
- 2.1.7、UDP 广播
- 2.1.7.2、广播
- 2.1.7.1、set_broadcast
- 2.1.8、UDP 组播
- 2.1.8.1、组播
- 2.1.8.2、set_multicast_loop_v4 和 set_multicast_loop_v6
- 2.1.8.3、set_multicast_ttl_v4 和 set_multicast_ttl_v6
- 2.1.8.4、leave_multicast_v4 和 leave_multicast_v6
- 2.1.8.5、join_multicast_v4 和 join_multicast_v6
- 2.1.9、set_ttl
- 2.1.10、set_nonblocking
- 总结
前言
本章节讲解 Rust 标准库(std::net 模块)操作 TCP 和 UDP 编程
主要教材参考 《The Rust Programming Language》
主要教材参考 《Rust For Rustaceans》
主要教材参考 《The Rustonomicon》
主要教材参考 《Rust 高级编程》
一、 TCP
1.1、std::net::TcpListener
1.1.1、bind
TCP 服务端使用 std::net::TcpListener::bind 方法来监听IP地址和端口。该方法定义如下
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener>
我们可以看到泛型参数 A 为 ToSocketAddrs 其实是一个 SocketAddr 的数组,我们可以使用 字符串方式来调用该方法 也可以使用数组的方式来使用。
use std::net::{SocketAddr, TcpListener};
fn main(){let listener = TcpListener::bind("127.0.0.1:3000").unwrap();let addrs = [SocketAddr::from(([127, 0, 0, 1], 80)),SocketAddr::from(([127, 0, 0, 1], 443)),];let listener = TcpListener::bind(&addrs[..]).unwrap();
}
两种方式调用都可以,第二种就是绑定 80端口失败,绑定端口443;
1.1.2、try_clone 方法
为 socket 创建一个新的句柄 ,两个句柄都可以用于接受传入的链接。
1.1.3、accept 方法
pub fn accept(&self) -> Result<(TcpStream, SocketAddr)>
从 监听器上接收一个新的连接,该方法返回 Result 。
use std::net::TcpListener;
#![allow(unused)]
fn main() {let listener = TcpListener::bind("127.0.0.1:8080").unwrap();match listener.accept() {Ok((_socket, addr)) => println!("new client: {addr:?}"),Err(e) => eprintln!("couldn't get client: {e:?}"),}
}
1.1.4、incoming 方法
返回监听器上正在接收连接的迭代器,迭代器永远不会返回None,也不会产生一个 SokcetAddr 结构,相当于循环调用 accept 。
use std::net::{TcpListener, TcpStream};fn handle_connection(stream: TcpStream) {//...
}fn main() -> std::io::Result<()> {let listener = TcpListener::bind("127.0.0.1:80")?;for stream in listener.incoming() {match stream {Ok(stream) => {handle_connection(stream);}Err(e) => { /* connection failed */ }}}Ok(())
}
1.1.5、into_incoming 方法
这是一个 仅限 nightly 使用的实验性 API,参考 https://github.com/rust-lang/rust/pull/88339
#![feature(tcplistener_into_incoming)]
use std::net::{TcpListener, TcpStream};fn listen_on(port: u16) -> impl Iterator<Item = TcpStream> {let listener = TcpListener::bind(("127.0.0.1", port)).unwrap();listener.into_incoming().filter_map(Result::ok) /* Ignore failed connections */
}fn main() -> std::io::Result<()> {for stream in listen_on(80) {/* handle the connection here */}Ok(())
}
1.1.6、ttl 相关方法
pub fn set_ttl(&self, ttl: u32) -> Result<()>
pub fn ttl(&self) -> Result<u32>
socket 发送 internet 协议数据包的生存时间值。
1.1.7、set_nonblocking
将 TCP 流设置成阻塞或非阻塞方式。
use std::io;
use std::net::TcpListener;let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
listener.set_nonblocking(true).expect("Cannot set non-blocking");for stream in listener.incoming() {match stream {Ok(s) => {// do something with the TcpStreamhandle_connection(s);}Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {// wait until network socket is ready, typically implemented// via platform-specific APIs such as epoll or IOCPwait_for_fd();continue;}Err(e) => panic!("encountered IO error: {e}"),}
}
1.2、地址相关类
1.2.1、Ipv4Addr/IpV6Addr/IpAddr
IpAddr 枚举
pub enum IpAddr {V4(Ipv4Addr),V6(Ipv6Addr),
}
使用方式
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};#![allow(unused)]
fn main() {let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));assert_eq!("::1".parse(), Ok(localhost_v6));assert_eq!(localhost_v4.is_ipv6(), false);assert_eq!(localhost_v4.is_ipv4(), true);
}
1.2.2、SocketAddr/SocketAddrV4/SocketAddrV6
同样 SocketAddr 是一个枚举
pub enum SocketAddr {V4(SocketAddrV4),V6(SocketAddrV6),
}
使用用例:
use std::net::{Ipv4Addr, SocketAddrV4};
use std::net::{Ipv6Addr, SocketAddrV6};fn main(){let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);assert_eq!("127.0.0.1:8080".parse(), Ok(socket));assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));assert_eq!(socket.port(), 8080);let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));assert_eq!(socket.port(), 8080);
}
1.3、std::net::TCPStream
使用 std::net::TCPStream 可以连接服务器、进行数据读取、写入数据;
1.3.1、connect 方法连接服务器
打开一个 Tcp 连接到远程主机。
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<TcpStream>
使用
use std::net::TcpStream;if let Ok(stream) = TcpStream::connect("127.0.0.1:8080") {println!("Connected to the server!");
} else {println!("Couldn't connect to server...");
}
1.3.2、connect_timeout
pub fn connect_timeout(addr: &SocketAddr,timeout: Duration
) -> Result<TcpStream>
在超时时间内打开一个远程主机的TCP连接。
1.3.3、shutdown
pub fn shutdown(&self, how: Shutdown) -> Result<()>
关闭连接读、写或都关闭。该函数将导致指定部分上的所有挂起和未来的I/O 立即返回一个适当的值。
特定平台的行为
- Linux 第二次调用将返回· OK(())·
- macOS;将返回 ErrorKind::NotConnected, 将来可能会改变
1.3.4、try_clone
pub fn try_clone(&self) -> Result<TcpStream>
1.3.5、set_read_timeout 和 set_write_timeout
pub fn set_read_timeout(&self, dur: Option<Duration>) -> Result<()>
pub fn set_write_timeout(&self, dur: Option<Duration>) -> Result<()>
如果指定为 None 读取调用将无限期阻塞,如果传入 0 Duration 。则返回Err。
特定平台行为:每当设置此项导致读取超时,平台可能返回不同的错误代码
- Unix:返回一个类型为 WouldBlock 错误
- Windows:可能返回 timeout;
1.3.6、peek
从连接上读取数据,不从队列中删除数据,如果成功返回已peek的字节数,连续调用返回相同的数据。
这是通过将MSG_PEEK作为一个标志传递给底层的recv系统调用来实现的。
pub fn peek(&self, buf: &mut [u8]) -> Result<usize>
1.3.7、set_linger
这是一个 nightly 版本的 实验性 API。
pub fn set_linger(&self, linger: Option<Duration>) -> Result<()>
如果设置了 SO_LINGER,系统尝试发送挂起数据时 ,sokect 将在指定时间内保持打开状态,否则系统会立即关闭套接字 或等待默认超时。
#![allow(unused)]
#![feature(tcp_linger)]
fn main() {
use std::net::TcpStream;
use std::time::Duration;let stream = TcpStream::connect("127.0.0.1:8080").expect("Couldn't connect to the server...");
stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed");
}
1.3.8、set_nodelay
Rust 标准库中的 TCP 流默认启用了 Nagle 的算法,它会避免高频发送小量的数据包,所以数据不会总是立即发送,这会对一些场合的应用产生影响(Rust TCP/Websocket 连接延迟波动)。
设置为 true 之后,会禁用 Nagle 算法。
pub fn set_nodelay(&self, nodelay: bool) -> Result<()>
示例
use std::net::TcpStream;#![allow(unused)]
fn main() {let stream = TcpStream::connect("127.0.0.1:8080").expect("Couldn't connect to the server...");stream.set_nodelay(true).expect("set_nodelay call failed");
}
二、 std::net::UdpSocket
可以用于 UDP 协议通信,通常用于低延迟比保证传输更重要的场景,例如:音频/视频流、网络发现等。
2.1.1、bind 方法
pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket>
从给定地址创建一个 UdpSocket 对象。使用方法和 TCPListener 差不多
2.1.2、recv_from 方法
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
接受单个数据包信息,如果成功,返回读取的字节数和原始字节。函数必须使用有效字节数组调用,但必须有足够大小来保存消息字节,如果消息太长而无法转入所提供的缓存区则会丢弃多余的字节。
use std::net::UdpSocket;
#![allow(unused)]
fn main() {let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");let mut buf = [0; 10];let (number_of_bytes, src_addr) = socket.recv_from(&mut buf).expect("Didn't receive data");let filled_buf = &mut buf[..number_of_bytes];}
2.1.3、peek_from 方法
2.1.4、send_to 方法
发送数据到服务端
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> Result<usize>
返回成功写入的字节数。
use std::net::UdpSocket;
#![allow(unused)]
fn main() {let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");socket.send_to(&[0; 10], "127.0.0.1:4242").expect("couldn't send data");
}
2.1.5、try_clone 方法
2.1.6、set_read_timeout 和 set_write_timeout
2.1.7、UDP 广播
2.1.7.2、广播
广播是一种一对多的通信,即目的是将数据报发送到网络中的所有节点。对于点对点通信的情况不同,我们不必知道目标主机的IP地址,而是使用广播地址。
广播地址是一个逻辑地址,连接到网络的设备可以在该地址上接收数据包。
2.1.7.1、set_broadcast
pub fn set_broadcast(&self, broadcast: bool) -> Result<()>
pub fn broadcast(&self) -> Result<bool>
默认值为false,设置为true之后,会开启广播
2.1.8、UDP 组播
2.1.8.1、组播
广播效率低下,因为数据包被发现倒网络中的所有节点,而不管他们是否有兴趣接收通信,这可能是一种资源浪费。多播解决了这个问题,并且只向感兴趣的消费者发送数据包
其中多播地址代表每个组。在IPv4 中,224.0.0.0 到 239.255.255.255 之间的任何地址都可以用作多播地址。只有订阅组的那些节点才能接收传送到该组的数据包。
2.1.8.2、set_multicast_loop_v4 和 set_multicast_loop_v6
获取此套接字的 IP_MULTICAST_LOOP 选项的值。
2.1.8.3、set_multicast_ttl_v4 和 set_multicast_ttl_v6
设置组播 ttl 超时时间
2.1.8.4、leave_multicast_v4 和 leave_multicast_v6
接收端离开组播
2.1.8.5、join_multicast_v4 和 join_multicast_v6
接收端加入组播地址才能接收数据。
2.1.9、set_ttl
设置超时时间
2.1.10、set_nonblocking
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
总结
以上就是今天要讲的内容
相关文章:

【跟小嘉学 Rust 编程】二十一、网络编程
系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

一文了解聚合支付
第四方支付是相对于第三方支付而提出的概念,又被称为“聚合支付”是指通过聚合第三方支付平台、合作银行、等多种支付工具进行的综合支付服务。 简言而之,把支付接口聚合到一个平台上面,来给商家或者个人来提供支付服务。 第四方支付集中了各…...

118.杨辉三角
一、题目 118. 杨辉三角 - 力扣(LeetCode) 二、代码 class Solution { public:vector<vector<int>> generate(int numRows) {vector<vector<int>>data(numRows);for(int i0;i<numRows;i){data[i].resize(i1);//扩容data[i]…...

第7节——渲染列表+Key作用
一、列表渲染 我们再react中如果渲染列表,一般使用map方法进行渲染 import React from "react";export default class LearnJSX2 extends React.Component {state {infos: [{name: "张三",age: 18,},{name: "李四",age: 20,},{nam…...

NTP服务器时间配置
简介 ntp服务器是一个同步时间都服务器。 开启ntpd 1.查看状态(可以看到状态为:inactive,也就是没有启动ntp服务) [rootlocalhost]$ systemctl status ntpd ● ntpd.service - Network Time ServiceLoaded: loaded (/usr/lib/…...

vulhub之MinIO信息泄露漏洞(CVE-2023-28432)
文章目录 0x01 前言0x02 漏洞描述0x03 影响范围0x04 漏洞复现1.启动环境2.查看端口3.构造POC 0x05 修复建议 0x01 前言 本次测试仅供学习使用,如若非法他用,与本文作者无关,需自行负责!!! 0x02 漏洞描述 …...

C语言:递归思想及实例详解
简介:在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。通过函数的自调用化繁为简。 递归可以说是编程中最神奇的一种算法。因为我们有时候可能不能完全明晰代码的运行过程,但是我们却知道代码可以跑出正确的结果。而当我们使…...

好题分享0
P2141 [NOIP2014 普及组] 珠心算测验 原题链接 : [NOIP2014 普及组] 珠心算测验 - 洛谷 思路 : 用哈希表来存出现过的两数之和,最后ans即可 代码 : #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define end…...

python的asyncio事件循环
一、介绍 asyncio是Python标准库中的一个异步编程框架,它提供了一个事件循环(event loop),用于协调异步任务的执行和结果的返回。在asyncio中,事件循环是一个非常重要的概念,它是异步编程的核心。 事件循…...

QT day1登录界面设计
要设计如下图片: 代码如下: main.cpp widget.h widget.cpp 运行效果: 2,思维导图...

(一)KITTI数据集用于3D目标检测
KITTI数据集介绍 数据基本情况 KITTI是德国卡尔斯鲁厄科技学院和丰田芝加哥研究院开源的数据集,最早发布于2012年03月20号。 对应的论文Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite发表在CVPR2012上。 KITTI数据集搜集自德国卡尔斯鲁厄市&…...

手写Promise完整介绍
Promise是一种用于处理异步操作的机制,它可以将异步操作的结果以同步的方式进行处理和返回。在JavaScript中,Promise是一种内置对象,但我们也可以手动实现一个Promise类来更好地理解其原理和工作方式。 Promise的特性 首先,让我…...

【kubernetes系列】Calico原理及配置
概述 Calico是针对容器,虚拟机和基于主机的本机工作负载的开源网络和网络安全解决方案。 Calico支持广泛的平台,包括Kubernetes,OpenShift,Docker EE,OpenStack和裸机服务。 Calico在每个计算节点都利用Linux Kernel实…...

RabbitMQ 的快速使用
docker部署rabbitmq # management才有管理页面 docker pull rabbitmq:management# 新建容器并运行 docker run \-e RABBITMQ_DEFAULT_USERadmin \ -e RABBITMQ_DEFAULT_PASSadmin \ -v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 \-itd \ra…...

VUE3添加全局变量
全局变量的添加 在vue3.0中注入全局方法不是在prototype上挂载了,而是添加在config.globalProperties属性上。 //main.js import { createApp } from "vue"; import App from "./App.vue";const app createApp(App); app.config.globalPrope…...

JavaScript基础语法01——初识JavaScript
哈喽,大家好,我是雷工! 最近有项目用到KingFusion软件,由于KingFusion是B/S架构的客户端组态软件,因此在学习KingFusion产品时会涉及许多前端的知识。 像JavaScript语言就是需要用的,俗话说:活到…...

家宽用户家庭网的主要质量问题是什么?原因有哪些
1 引言 截至2020年底,我国家庭宽带(以下简称“家宽”)普及率已达到96%。经过一年多的发展,当前,家庭宽带的市场空间已经饱和。运营商在家宽市场的竞争也随之从新增用户数的竞争转移到家宽品质的竞争。 早期运营商的家…...

ZooKeeper的典型应用场景及实现
文章目录 1、典型应用场景及实现1.1、 数据发布/订阅1.1.1、配置管理案列 1.2、负载均衡1.3、命名服务1.4、分布式协调/通知1.4.1、一种通用的分布式系统机器间通信方式 1.5、集群管理1.6、Master选举1.7、分布式锁1.7.1、排他锁1.7.2、共享锁 1.8、分布式队列 2、ZooKeeper在大…...

智能安全帽~生命体征检测与危险气体检测一体化集成设计还是蓝牙无线外挂式方式好?
生命体征(心率、血氧等)检测&上报平台,危险气体采集&上报平台,是智能安全帽产品中常见的两种选配件,它们的实现有两种典型的模式: 1)将传感器集成到主板上,做成一体化的智能…...

【Java并发】聊聊对象内存布局和syn锁升级过程
对象存储解析:一个空Object对象到底占据多少内存? 对象内存布局 Mark Word占用8字节,类型指针占用8个字节,对象头占用16个字节。 好了,我们来看一下一个Object对占用多少空间, 因为java默认是开启压缩…...

【档案专题】八、电子档案鉴定与销毁
导读:主要针对电子档案鉴定与销毁相关内容介绍。对从事电子档案管理信息化的职业而言,不断夯实电子档案管理相关理论基础是十分重要。只有通过不断梳理相关知识体系和在实际工作当中应用实践,才能走出一条专业化加职业化的道路,从…...

进程与子进程
一、子进程 1.fork()创建子进程 一个现有的进程可以调用 fork()函数创建一个新的进程,调用 fork()函数的进程称为父进程,由 fork()函数创建出来的进程被称为子进程(child process)。(使用该函数需要包含头文件<uni…...

如何对MySQL和MariaDB中的查询和表进行优化-提升查询效率
前言 MySQL和MariaDB是数据库管理系统的流行选择。两者都使用SQL查询语言来输入和查询数据。 尽管SQL查询是简单易学的命令,但并不是所有的查询和数据库函数都具有相同的效率。随着你存储的信息量的增长,如果你的数据库支持一个网站,随着网…...

【Android】关于binder_calls_stats服务
Android 9上有了binder_calls_stats服务,提供了java层的binder统计, Android中的Binder Call Stats(Binder调用统计)是一项用于监控和记录Android系统中Binder通信的统计信息的功能。Binder是Android中的一种进程间通信ÿ…...

给前端返回http链接,由于浏览器缓存不能获取到最新资源怎么办?
1、问题描述 今天在工作中接到这样一个需求,接收前端的图片文件并上传到远程,将原有图片覆盖并返回一个http链接以供前端展示。用户使用后反馈没有修改成功,上了远程拉图片发现已经修改了,但是用户浏览器还是老的图片。排查原因是…...

【Java Web】检查用户登录状态,防止用户访问到非法页面
使用拦截器 在方法前标注自定义注解拦截所有请求,只处理带有该注解的方法 自定义注解: 常用元注解:Target, Rentention, Document, Inherited如何读取注解: - Method.getDeclaredAnnotations() - Method.getAnnotaion(Class<T&…...

数学建模——校园供水系统智能管理
import pandas as pd data1pd.read_excel("C://Users//JJH//Desktop//E//附件_一季度.xlsx") data2pd.read_excel("C://Users//JJH//Desktop//E//附件_二季度.xlsx") data3pd.read_excel("C://Users//JJH//Desktop//E//附件_三季度.xlsx") data4…...

分布式集群——搭建Hadoop环境以及相关的Hadoop介绍
系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 前言 一 hadoop的相关概念 1.1 Hadoop概念 补充:块的存储 1.2 HDFS是什么 1.3 三种节点的功能 I、NameNode节点 II、fsimage与edits…...

Python的os.walk()函数使用案例
在Python中,os模块是一个非常实用的工具,它可以让我们与操作系统进行交互,操作文件和目录。在本文中,我们将详细介绍os模块中的遍历文件功能,并通过具体案例和使用场景来解释。 首先,导入os模块。在Pytho…...

学习JAVA打卡第四十五天
StringBuffer类 StringBuffer对象 String对象的字符序列是不可修改的,也就是说,String对象的字符序列的字符不能被修改、删除,即String对象的实体是不可以再发生变化,例如:对于 StringBuffer有三个构造方法ÿ…...