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

【跟小嘉学 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
  • 总结

前言

本章节讲解 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 编程】五、使用结构体关联结构化数据 【跟小嘉学…...

一文了解聚合支付

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

118.杨辉三角

一、题目 118. 杨辉三角 - 力扣&#xff08;LeetCode&#xff09; 二、代码 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中如果渲染列表&#xff0c;一般使用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.查看状态&#xff08;可以看到状态为&#xff1a;inactive&#xff0c;也就是没有启动ntp服务&#xff09; [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 前言 本次测试仅供学习使用&#xff0c;如若非法他用&#xff0c;与本文作者无关&#xff0c;需自行负责&#xff01;&#xff01;&#xff01; 0x02 漏洞描述 …...

C语言:递归思想及实例详解

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

好题分享0

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

python的asyncio事件循环

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

QT day1登录界面设计

要设计如下图片&#xff1a; 代码如下&#xff1a; main.cpp widget.h widget.cpp 运行效果&#xff1a; 2&#xff0c;思维导图...

(一)KITTI数据集用于3D目标检测

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

手写Promise完整介绍

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

【kubernetes系列】Calico原理及配置

概述 Calico是针对容器&#xff0c;虚拟机和基于主机的本机工作负载的开源网络和网络安全解决方案。 Calico支持广泛的平台&#xff0c;包括Kubernetes&#xff0c;OpenShift&#xff0c;Docker EE&#xff0c;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上挂载了&#xff0c;而是添加在config.globalProperties属性上。 //main.js import { createApp } from "vue"; import App from "./App.vue";const app createApp(App); app.config.globalPrope…...

JavaScript基础语法01——初识JavaScript

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

家宽用户家庭网的主要质量问题是什么?原因有哪些

1 引言 截至2020年底&#xff0c;我国家庭宽带&#xff08;以下简称“家宽”&#xff09;普及率已达到96%。经过一年多的发展&#xff0c;当前&#xff0c;家庭宽带的市场空间已经饱和。运营商在家宽市场的竞争也随之从新增用户数的竞争转移到家宽品质的竞争。 早期运营商的家…...

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在大…...

智能安全帽~生命体征检测与危险气体检测一体化集成设计还是蓝牙无线外挂式方式好?

生命体征&#xff08;心率、血氧等&#xff09;检测&上报平台&#xff0c;危险气体采集&上报平台&#xff0c;是智能安全帽产品中常见的两种选配件&#xff0c;它们的实现有两种典型的模式&#xff1a; 1&#xff09;将传感器集成到主板上&#xff0c;做成一体化的智能…...

【Java并发】聊聊对象内存布局和syn锁升级过程

对象存储解析&#xff1a;一个空Object对象到底占据多少内存&#xff1f; 对象内存布局 Mark Word占用8字节&#xff0c;类型指针占用8个字节&#xff0c;对象头占用16个字节。 好了&#xff0c;我们来看一下一个Object对占用多少空间&#xff0c; 因为java默认是开启压缩…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解

文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一&#xff1a;HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二&#xff1a;Floyd 快慢指针法&#xff08;…...

【题解-洛谷】P10480 可达性统计

题目&#xff1a;P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图&#xff0c;分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M&#xff0c;接下来 M M M 行每行两个整数 x , y x,y x,y&#xff0c;表示从 …...

无需布线的革命:电力载波技术赋能楼宇自控系统-亚川科技

无需布线的革命&#xff1a;电力载波技术赋能楼宇自控系统 在楼宇自动化领域&#xff0c;传统控制系统依赖复杂的专用通信线路&#xff0c;不仅施工成本高昂&#xff0c;后期维护和扩展也极为不便。电力载波技术&#xff08;PLC&#xff09;的突破性应用&#xff0c;彻底改变了…...