940 words
UDP包大小与网络传输的基础UDP(用户数据报协议)是一种无连接的传输层协议,以其低延迟和简单性著称。但UDP不提供可靠性保证,数据包可能丢失、重复或乱序。包大小是影响UDP传输质量的关键因素: 123456UDP包结构:+---------------------+| 源端口 | 目的端口 | 2+2字节| 长度 | 校验和 | 2+2字节| 数据(payload) | 0-65,507字节+---------------------+ MTU:网络传输的物理限制MTU(Maximum Transmission Unit)是网络链路能传输的最大数据包大小。常见MTU值: 以太网:1500字节 PPPoE(ADSL):1492字节 蜂窝网络(4G/5G):1400-1500字节 UDP有效载荷 = MTU - IP头(20字节) - UDP头(8字节) 标准以太网:1500 - 28 = 1472字节 超过MTU的包会被分片传输 包大小与丢包率的理论关系分片重组问题当UDP包超过MTU时: 12345678910g...
1.3k words
Rust生命周期终于讲到Rust最重要的机制之一了,生命周期机制 我们先复习一下垂悬引用 12345678910{ let r; { let x = 5; r = &x; } println!("r: {}", r);} 这一段代码是编译失败的,原因如下 我们可以看到有两个作用域 a和b,但是其实生命周期也是类似的概念,r的生命周期中a的范围里,x的生命周期中b的范围内 r保存的x的引用,当x销毁之后,r的引用也就失效了,因此也就产生了垂悬引用 这里有一个案例 1234567fn longer(s1: &str, s2: &str) -> &str { if s2.len() > s1.len() { s2 } else { s1 }} 接收两个字符串引用,返回两个字符串引用中较长的一个 这段代码...
1.5k words
泛型泛型编程是现代编程语言中重要的机制 C++是通过模板来实现泛型的,而C语言中是没有泛型的 泛型是用来表达抽象类型的机制,用于功能确定,但是数据类型不确定的类型 函数中的泛型下面这个是没有泛型版本的取数组中最大值的函数 12345678910111213141516fn max(array: &[i32]) -> i32 { let mut max_index = 0; let mut i = 1; while i < array.len() { if array[i] > array[max_index] { max_index = i; } i += 1; } array[max_index]}fn main() { let a = [2, 4, 6, 3, 1]; println!("max = {}", max(&a));&...
1.4k words
包管理Rust的包管理有三个重要的概念,分别是箱、包、模块 箱(Crate)这个Crate是二进制程序文件或者是苦文件,存在于包中 是树状结构,树根是编译器开始运行时编译的源文件所编译的程序 二进制程序文件不一定是可执行文件,只能确定是包含沐白哦机器语言的文件,文件格式主要取决于编译环境 包(Package)我们使用cargo new一个Rust工程时,这个工程其实就是一个包,包必须由Cargo.toml文件来管理,主要是描述包的基本信息和依赖项 一个包最多包含一个库Crate,但是可以包含任意二进制Crate,但是至少包含一个Crate 当我们创建完项目之后,会有一个main.rs,这其实就意味着这是一个二进制项目 模块(Module)Rust中组织的单位是模块,模块有很多中声明方式 例如 1234567891011mod nation { mod government { fn govern() {} } mod congress { fn legislate() ...
1.6k words
切片类型切片(Slice)是对数据值的部分“引用” 我们可以从一个数据集合中取一部分来使用 字符串切片例如 12345678fn main() { let s = String::from("broadcast"); let part1 = &s[0..5]; let part2 = &s[5..9]; println!("{}={}+{}", s, part1, part2);} 这里的0..5是前闭后开区间实际上内存上是这样的 有一些简便的写法,可以这样写 123..y 等价于 0..yx.. 等价于位置 x 到数据结束.. 等价于位置 0 到结束 被切片引用的字符串是不允许被修改的,除此之外,我们需要区分str和String这两个字符串类型 前者指的是堆内存中的字符串,我们可以理解为常量字符串,用的时候是作为&str引用使用的 String实际上是一种数据类型,类似于C++中的string类,有追加,清...
950 words
基于文件锁的进程监控机制在分布式系统或者一些需要长期运行的程序中,我们经常需要确保某些关键进程(如日志收集程序、服务守护进程等)一直在运行。如果进程意外退出或者崩溃,我们需要能够检测到,并及时做出响应。 在这种情况下,”文件锁(File Lock)” 机制是一种简单但有效的方式。本文将介绍基于文件的进程监控方式,并通过一个例子来帮助理解。 进程监控的核心思路通常,我们希望有一个监控机制,它能够: 确保某个进程正在运行 如果进程异常退出,可以检测到并触发报警或重启 机制本身要足够简单和可靠 一种常见的做法是使用 “PID 文件” 进行监控。 什么是 PID 文件?PID(Process ID)是操作系统为每个正在运行的进程分配的唯一标识符。我们可以让一个程序在启动时,将自己的 PID 写入一个文件(通常存放在 /var/run/ 目录下),然后定期检查这个文件。 如何监控进程? 程序启动时,创建一个 PID 文件,并把自己的 PID 写进去。 监控程序定期检查这个 PID 文件,看看里面记录的进程是否还在运行。 如果 PID 文件不存在,或者进程已经不在运行,就可以触发报警或自...
1.6k words
Rust所有权C/C++中我们对于堆内存通常需要自己手动管理,手动申请和释放,即便有了智能指针,对于效率的影响和安全性问题也没有完全解决 Rust为了高效的使用和管理内存,以及对安全性的考量,提出了所有权的概念以及一系列规则 所有权规则所有权有三条核心规则 Rust中的每个值都有一个隐含的变量,称为所有者 一个值 同一时刻只能有一个所有者 当所有者离开作用域时,值会被丢弃(调用drop函数释放资源) 12345678fn main() { let s1 = String::from("Hello"); // s1 是 "Hello" 的所有者 let s2 = s1; // s1 的所有权被转移给 s2,s1 失效 // println!("{}", s1); // ❌ 编译错误:s1 已经失去所有权 println!("{}", s2); // ✅ s2 仍然是 "Hello" 的所有者...
1.8k words
Rust迭代器迭代器适用于对集合进行逐个遍历操作的对象 迭代器是通过iterator trait来定义的,需要我们实现next方法,用于返回迭代器的下一个元素,如果没有下一个元素应该返回None表示结束 其他默认实现的方法有map filter等 12345pub trait Iterator{ type Item; fn next(&mut self) -> Option<Self::Item>;} 迭代器有以下的一些特性 惰性求值:这个意思是迭代器本身不回立即进行任何计算或者操作,除非我们显示的要求获取数据,迭代器才会返回数据,这样就可以避免不必要的计算 所有权和借用检查:迭代器严格遵守所有权和借用的规则,具体是什么我们后面会讲到,这里我们只要知道,这是为了避免数据竞争和内存错误 链式调用:Rust迭代器支持链式调用 抽象和通用性:Rust迭代器通过 Iterator trail实现抽象和通用性 迭代器的使用创建迭代器可以通过.iter() .iter_mut .into_iter()来创建迭代器 第一个是不可变引用...