深圳企業(yè)網(wǎng)站建設(shè)制作網(wǎng)絡(luò)流量統(tǒng)計工具
系列文章目錄
【跟小嘉學(xué) Rust 編程】一、Rust 編程基礎(chǔ)
【跟小嘉學(xué) Rust 編程】二、Rust 包管理工具使用
【跟小嘉學(xué) Rust 編程】三、Rust 的基本程序概念
【跟小嘉學(xué) Rust 編程】四、理解 Rust 的所有權(quán)概念
【跟小嘉學(xué) Rust 編程】五、使用結(jié)構(gòu)體關(guān)聯(lián)結(jié)構(gòu)化數(shù)據(jù)
【跟小嘉學(xué) Rust 編程】六、枚舉和模式匹配
【跟小嘉學(xué) Rust 編程】七、使用包(Packages)、單元包(Crates)和模塊(Module)來管理項目
【跟小嘉學(xué) Rust 編程】八、常見的集合
【跟小嘉學(xué) Rust 編程】九、錯誤處理(Error Handling)
【跟小嘉學(xué) Rust 編程】十一、編寫自動化測試
【跟小嘉學(xué) Rust 編程】十二、構(gòu)建一個命令行程序
【跟小嘉學(xué) Rust 編程】十三、函數(shù)式語言特性:迭代器和閉包
【跟小嘉學(xué) Rust 編程】十四、關(guān)于 Cargo 和 Crates.io
【跟小嘉學(xué) Rust 編程】十五、智能指針(Smart Point)
【跟小嘉學(xué) Rust 編程】十六、無畏并發(fā)(Fearless Concurrency)
【跟小嘉學(xué) Rust 編程】十七、面向?qū)ο笳Z言特性
【跟小嘉學(xué) Rust 編程】十八、模式匹配(Patterns and Matching)
【跟小嘉學(xué) Rust 編程】十九、高級特性
【跟小嘉學(xué) Rust 編程】二十、進階擴展
【跟小嘉學(xué) Rust 編程】二十一、網(wǎng)絡(luò)編程
文章目錄
- 系列文章目錄
- @[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 相關(guān)方法
- 1.1.7、set_nonblocking
- 1.2、地址相關(guān)類
- 1.2.1、Ipv4Addr/IpV6Addr/IpAddr
- 1.2.2、SocketAddr/SocketAddrV4/SocketAddrV6
- 1.3、std::net::TCPStream
- 1.3.1、connect 方法連接服務(wù)器
- 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
- 總結(jié)
文章目錄
- 系列文章目錄
- @[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 相關(guān)方法
- 1.1.7、set_nonblocking
- 1.2、地址相關(guān)類
- 1.2.1、Ipv4Addr/IpV6Addr/IpAddr
- 1.2.2、SocketAddr/SocketAddrV4/SocketAddrV6
- 1.3、std::net::TCPStream
- 1.3.1、connect 方法連接服務(wù)器
- 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
- 總結(jié)
前言
本章節(jié)講解 Rust 標(biāo)準(zhǔn)庫(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 服務(wù)端使用 std::net::TcpListener::bind 方法來監(jiān)聽IP地址和端口。該方法定義如下
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener>
我們可以看到泛型參數(shù) A 為 ToSocketAddrs 其實是一個 SocketAddr 的數(shù)組,我們可以使用 字符串方式來調(diào)用該方法 也可以使用數(shù)組的方式來使用。
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();
}
兩種方式調(diào)用都可以,第二種就是綁定 80端口失敗,綁定端口443;
1.1.2、try_clone 方法
為 socket 創(chuàng)建一個新的句柄 ,兩個句柄都可以用于接受傳入的鏈接。
1.1.3、accept 方法
pub fn accept(&self) -> Result<(TcpStream, SocketAddr)>
從 監(jiān)聽器上接收一個新的連接,該方法返回 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 方法
返回監(jiān)聽器上正在接收連接的迭代器,迭代器永遠不會返回None,也不會產(chǎn)生一個 SokcetAddr 結(jié)構(gòu),相當(dāng)于循環(huán)調(diào)用 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 相關(guān)方法
pub fn set_ttl(&self, ttl: u32) -> Result<()>
pub fn ttl(&self) -> Result<u32>
socket 發(fā)送 internet 協(xié)議數(shù)據(jù)包的生存時間值。
1.1.7、set_nonblocking
將 TCP 流設(shè)置成阻塞或非阻塞方式。
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、地址相關(guān)類
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 可以連接服務(wù)器、進行數(shù)據(jù)讀取、寫入數(shù)據(jù);
1.3.1、connect 方法連接服務(wù)器
打開一個 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>
在超時時間內(nèi)打開一個遠程主機的TCP連接。
1.3.3、shutdown
pub fn shutdown(&self, how: Shutdown) -> Result<()>
關(guān)閉連接讀、寫或都關(guān)閉。該函數(shù)將導(dǎo)致指定部分上的所有掛起和未來的I/O 立即返回一個適當(dāng)?shù)闹怠?/p>
特定平臺的行為
- Linux 第二次調(diào)用將返回· 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 讀取調(diào)用將無限期阻塞,如果傳入 0 Duration 。則返回Err。
特定平臺行為:每當(dāng)設(shè)置此項導(dǎo)致讀取超時,平臺可能返回不同的錯誤代碼
- Unix:返回一個類型為 WouldBlock 錯誤
- Windows:可能返回 timeout;
1.3.6、peek
從連接上讀取數(shù)據(jù),不從隊列中刪除數(shù)據(jù),如果成功返回已peek的字節(jié)數(shù),連續(xù)調(diào)用返回相同的數(shù)據(jù)。
這是通過將MSG_PEEK作為一個標(biāo)志傳遞給底層的recv系統(tǒng)調(diào)用來實現(xiàn)的。
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<()>
如果設(shè)置了 SO_LINGER,系統(tǒng)嘗試發(fā)送掛起數(shù)據(jù)時 ,sokect 將在指定時間內(nèi)保持打開狀態(tài),否則系統(tǒng)會立即關(guān)閉套接字 或等待默認(rèn)超時。
#![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 標(biāo)準(zhǔn)庫中的 TCP 流默認(rèn)啟用了 Nagle 的算法,它會避免高頻發(fā)送小量的數(shù)據(jù)包,所以數(shù)據(jù)不會總是立即發(fā)送,這會對一些場合的應(yīng)用產(chǎn)生影響(Rust TCP/Websocket 連接延遲波動)。
設(shè)置為 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 協(xié)議通信,通常用于低延遲比保證傳輸更重要的場景,例如:音頻/視頻流、網(wǎng)絡(luò)發(fā)現(xiàn)等。
2.1.1、bind 方法
pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket>
從給定地址創(chuàng)建一個 UdpSocket 對象。使用方法和 TCPListener 差不多
2.1.2、recv_from 方法
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)>
接受單個數(shù)據(jù)包信息,如果成功,返回讀取的字節(jié)數(shù)和原始字節(jié)。函數(shù)必須使用有效字節(jié)數(shù)組調(diào)用,但必須有足夠大小來保存消息字節(jié),如果消息太長而無法轉(zhuǎn)入所提供的緩存區(qū)則會丟棄多余的字節(jié)。
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 方法
發(fā)送數(shù)據(jù)到服務(wù)端
pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> Result<usize>
返回成功寫入的字節(jié)數(shù)。
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、廣播
廣播是一種一對多的通信,即目的是將數(shù)據(jù)報發(fā)送到網(wǎng)絡(luò)中的所有節(jié)點。對于點對點通信的情況不同,我們不必知道目標(biāo)主機的IP地址,而是使用廣播地址。
廣播地址是一個邏輯地址,連接到網(wǎng)絡(luò)的設(shè)備可以在該地址上接收數(shù)據(jù)包。
2.1.7.1、set_broadcast
pub fn set_broadcast(&self, broadcast: bool) -> Result<()>
pub fn broadcast(&self) -> Result<bool>
默認(rèn)值為false,設(shè)置為true之后,會開啟廣播
2.1.8、UDP 組播
2.1.8.1、組播
廣播效率低下,因為數(shù)據(jù)包被發(fā)現(xiàn)倒網(wǎng)絡(luò)中的所有節(jié)點,而不管他們是否有興趣接收通信,這可能是一種資源浪費。多播解決了這個問題,并且只向感興趣的消費者發(fā)送數(shù)據(jù)包
其中多播地址代表每個組。在IPv4 中,224.0.0.0 到 239.255.255.255 之間的任何地址都可以用作多播地址。只有訂閱組的那些節(jié)點才能接收傳送到該組的數(shù)據(jù)包。
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
設(shè)置組播 ttl 超時時間
2.1.8.4、leave_multicast_v4 和 leave_multicast_v6
接收端離開組播
2.1.8.5、join_multicast_v4 和 join_multicast_v6
接收端加入組播地址才能接收數(shù)據(jù)。
2.1.9、set_ttl
設(shè)置超時時間
2.1.10、set_nonblocking
pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()>
總結(jié)
以上就是今天要講的內(nèi)容