系列文章目录
前言
实现Rust Udp组播。
一、项目创建
- cmd新建cargo工程目录
cargo new s1
- 切到s1目录新建两个子工程:udpclient,udpserver
cd s1
cargo new udpclient1
cargo new udpclient2
cargo new udpserver
- 修改s1目录下Cargo.toml添加子工程
[workspace]
members = ["tcpserver", "tcpclient1", "tcpclient2"]
二、Udp组播
- 编辑tcpclient1\src\main.rs,demo目录下执行命令
cargo run -p tcpclient1
use std::net::UdpSocket;
use std::thread;
fn main() {
let socket = UdpSocket::bind("127.0.0.1:1111").unwrap();
const COUNT: usize = 100;
loop {
let buf = [0x41; COUNT];
socket.send_to(&buf, "127.0.0.1:8888").unwrap();
thread::sleep(std::time::Duration::from_millis(1000));
}
}
- 编辑tcpclient2\src\main.rs,demo目录下执行命令
cargo run -p tcpclient2
use std::net::UdpSocket;
use std::thread;
fn main() {
let socket = UdpSocket::bind("127.0.0.1:2222").unwrap();
const COUNT: usize = 100;
loop {
let buf = [0x41; COUNT];
socket.send_to(&buf, "127.0.0.1:8888").unwrap();
thread::sleep(std::time::Duration::from_millis(1000));
}
}
- 编辑tcpserver\src\main.rs,demo目录下执行命令
cargo run -p tcpserver
use std::net::{Ipv4Addr, UdpSocket};
fn main() {
let socket = UdpSocket::bind("127.0.0.1:8888").unwrap();
let multicast_addr = Ipv4Addr::new(234, 2, 2, 2);
let inter = Ipv4Addr::new(0, 0, 0, 0);
socket.join_multicast_v4(&multicast_addr, &inter).unwrap();
let mut buf = [0u8; 65536];
loop {
let (amt, src) = socket.recv_from(&mut buf).unwrap();
println!("{}: {:?}", amt, src);
}
socket.leave_multicast_v4(&multicast_addr, &inter).unwrap();
}
- 效果
补充
- 补充1:crossbeam的一些例子
- Cargo.toml添加依赖
[dependencies]
crossbeam = "0.8"
- main.rs
// 使用 crossbeam 库和 SegQueue 实现线程间的通信与数据同步
use crossbeam::{self, queue::SegQueue, scope};
use std::{thread, time::Duration};
fn main() {
// 创建一个 SegQueue 实例用于线程间的数据传递
let seg_queue = SegQueue::new();
// 使用 crossbeam 的 scope 函数来创建一个作用域,内部可以并发执行多个任务
scope(|s| {
// 第一个任务:向队列中推入 0 到 9 的数字
s.spawn(|_| {
for i in 0..10 {
seg_queue.push(i);
println!("Thread 1: {}", i);
}
});
// 第二个任务:从队列中弹出数据并打印,重复执行五次
s.spawn(|_| {
let mut i = 0;
'outer: loop {
while let Some(item) = seg_queue.pop() {
println!("Thread 2: {}", item);
i += 1;
if i >= 5 {
break 'outer;
};
}
}
});
})
// 处理 scope 中的任务,如果有错误则.unwrap()会触发 panic
.unwrap();
// 主线程从队列中弹出剩余的数据并打印
while let Some(item) = seg_queue.pop() {
println!("Main Thread: {}", item);
}
}
- 输出
Thread 1: 0
Thread 2: 0
Thread 2: 1
Thread 1: 1
Thread 1: 2
Thread 1: 3
Thread 1: 4
Thread 1: 5
Thread 1: 7
Thread 1: 8
Thread 1: 9
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 2: 5
Main Thread: 6
Main Thread: 7
Main Thread: 8
Main Thread: 9
- 补充2:udpsocket+crossbeam无锁队列+数据筛选
- udpserver.rs
use crossbeam::{self, queue::SegQueue, scope};
use std::net::{Ipv4Addr, UdpSocket};
use std::{thread, time::Duration};
fn main() {
let socket = UdpSocket::bind("127.0.0.1:8888").unwrap();
let multicast_addr = Ipv4Addr::new(234, 2, 2, 2);
let inter = Ipv4Addr::new(0, 0, 0, 0);
socket.join_multicast_v4(&multicast_addr, &inter).unwrap();
let seg_queue = SegQueue::<u8>::new();
scope(|s| {
s.spawn(|_| loop {
let mut buf = [0; 1024];
let (number_of_bytes, _) = socket.recv_from(&mut buf).unwrap();
for i in 0..number_of_bytes {
seg_queue.push(buf[i]);
}
});
s.spawn(|_| loop {
let mut data = [0u8; 4];
let mut d1 = 0u8;
let mut d2 = 0u8;
let mut index = 0;
while let Some(item) = seg_queue.pop() {
if index == 0 {
if item == 1u8 {
d1 = item;
index += 1;
} else {
continue;
}
} else if index == 1 {
if item == 2u8 {
d2 = item;
data[0] = d1;
data[1] = d2;
index += 1;
} else {
index = 0;
continue;
}
} else {
data[index] = item;
if index == 3 {
index = 0;
println!("receive: {:#?}", data);
continue;
}
index += 1;
}
thread::sleep(Duration::from_millis(5));
}
});
})
.unwrap();
socket.leave_multicast_v4(&multicast_addr, &inter).unwrap();
}
- udpclient.rs
use std::net::UdpSocket;
use std::thread;
fn main() {
let socket = UdpSocket::bind("127.0.0.1:1111").unwrap();
const COUNT: usize = 10;
loop {
let mut buf = [0x41; COUNT];
for i in 0..COUNT {
buf[i] = (i + 1) as u8;
}
println!("send: {:#?}", buf);
socket.send_to(&buf, "127.0.0.1:8888").unwrap();
thread::sleep(std::time::Duration::from_millis(1000));
}
}
- 效果
- 补充3:数据流提取帧的一个算法
s.spawn(|_| {
let mut data = [0u8; 5];
let mut data_index = 0;
loop {
let mut buf = [0u8; 65535];
let (number_of_bytes, _) = socket.recv_from(&mut buf).unwrap();
let filled_buf = &mut buf[..number_of_bytes];
for i in 0..number_of_bytes {
if data_index == 0 {
if filled_buf[i] == 0x1 {
data[data_index] = filled_buf[i];
data_index += 1;
}
} else if data_index == 1 {
if filled_buf[i] == 0x2 {
data[data_index] = filled_buf[i];
data_index += 1;
} else {
data_index = 0;
}
} else if data_index == 4 {
if filled_buf[i] == 0x5 {
data[data_index] = filled_buf[i];
println!("algrithm2:{:#?}", data);
}
data_index = 0;
} else {
data[data_index] = filled_buf[i];
data_index += 1;
}
}
//for i in 0..number_of_bytes {
// seg_queue.push(buf[i]);
//}
}
});
总结
以上就是今天要讲的内容,本文仅仅简单介绍了rust Udp 组播的使用,而std::net提供了大量能使我们快速便捷地处理数据的函数和方法。