pub struct TcpSocket { /* private fields */ }展开描述
尚未转换为 TcpStream 或
TcpListener 的 TCP 套接字。
TcpSocket 包装了一个操作系统套接字,使调用者能够在建立 TCP 连接或接受传入连接之前配置套接字。调用者可以设置套接字选项,并使用套接字地址显式绑定套接字。
当 TcpSocket 值被丢弃时,底层套接字将被关闭。
仅当 TcpStream::connect 和 TcpListener::bind 使用的默认配置不满足所需用例时,才应直接使用 TcpSocket。
调用 TcpStream::connect("127.0.0.1:8080") 等价于:
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
let stream = socket.connect(addr).await?;
Ok(())
}调用 TcpListener::bind("127.0.0.1:8080") 等价于:
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
// On platforms with Berkeley-derived sockets, this allows to quickly
// rebind a socket, without needing to wait for the OS to clean up the
// previous one.
//
// On Windows, this allows rebinding sockets which are actively in use,
// which allows "socket hijacking", so we explicitly don't set it here.
// https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
socket.set_reuseaddr(true)?;
socket.bind(addr)?;
// Note: the actual backlog used by `TcpListener::bind` is platform-dependent,
// as Tokio relies on Mio's default backlog value configuration. The `1024` here is only
// illustrative and does not reflect the real value used.
let listener = socket.listen(1024)?;
Ok(())
}设置 TcpSocket 未明确提供的套接字选项,可以通过使用 AsRawFd/AsRawSocket 访问 RawFd/RawSocket,然后使用类似 socket2 的 crate 来设置选项。
实现§
Source§impl TcpSocket
impl TcpSocket
Sourcepub fn new_v4() -> Result<TcpSocket>
pub fn new_v4() -> Result<TcpSocket>
创建一个配置为 IPv4 的新套接字。
使用 AF_INET 和 SOCK_STREAM 调用 socket(2)。
§Returns
成功时返回新创建的 TcpSocket。如果遇到错误,则改为返回错误。
§示例
创建一个新的 IPv4 套接字并开始监听。
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.bind(addr)?;
let listener = socket.listen(128)?;
Ok(())
}Sourcepub fn new_v6() -> Result<TcpSocket>
pub fn new_v6() -> Result<TcpSocket>
创建一个配置为 IPv6 的新套接字。
使用 AF_INET6 和 SOCK_STREAM 调用 socket(2)。
§Returns
成功时返回新创建的 TcpSocket。如果遇到错误,则改为返回错误。
§示例
创建一个新的 IPv6 套接字并开始监听。
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "[::1]:8080".parse().unwrap();
let socket = TcpSocket::new_v6()?;
socket.bind(addr)?;
let listener = socket.listen(128)?;
Ok(())
}Sourcepub fn set_keepalive(&self, keepalive: bool) -> Result<()>
pub fn set_keepalive(&self, keepalive: bool) -> Result<()>
为该套接字设置 SO_KEEPALIVE 选项的值。
Sourcepub fn set_reuseaddr(&self, reuseaddr: bool) -> Result<()>
pub fn set_reuseaddr(&self, reuseaddr: bool) -> Result<()>
允许套接字绑定到正在使用的地址。
行为是平台特定的。更多细节请参阅目标平台的文档。
§示例
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.set_reuseaddr(true)?;
socket.bind(addr)?;
let listener = socket.listen(1024)?;
Ok(())
}Sourcepub fn reuseaddr(&self) -> Result<bool>
pub fn reuseaddr(&self) -> Result<bool>
获取该套接字上 SO_REUSEADDR 的设置值。
§示例
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.set_reuseaddr(true)?;
assert!(socket.reuseaddr().unwrap());
socket.bind(addr)?;
let listener = socket.listen(1024)?;
Ok(())
}Sourcepub fn set_send_buffer_size(&self, size: u32) -> Result<()>
pub fn set_send_buffer_size(&self, size: u32) -> Result<()>
为该套接字设置 TCP 发送缓冲区的大小。
在大多数操作系统上,这会设置 SO_SNDBUF 套接字选项。
Sourcepub fn send_buffer_size(&self) -> Result<u32>
pub fn send_buffer_size(&self) -> Result<u32>
返回该套接字的 TCP 发送缓冲区大小。
在大多数操作系统上,这就是 SO_SNDBUF 套接字选项的值。
请注意,如果此前已在此套接字上调用过 set_send_buffer_size,则此函数返回的值可能与提供给 set_send_buffer_size 的参数不同。原因如下:
- Most operating systems have minimum and maximum allowed sizes for the send buffer, and will clamp the provided value if it is below the minimum or above the maximum. The minimum and maximum buffer sizes are OS-dependent.
- Linux will double the buffer size to account for internal bookkeeping
data, and returns the doubled value from
getsockopt(2). As perman 7 socket:以字节为单位设置或获取最大套接字发送缓冲区。当使用
setsockopt(2)设置该值时,内核会将其加倍(以留出簿记开销的空间),getsockopt(2)返回的是加倍后的值。
Sourcepub fn set_recv_buffer_size(&self, size: u32) -> Result<()>
pub fn set_recv_buffer_size(&self, size: u32) -> Result<()>
为该套接字设置 TCP 接收缓冲区的大小。
在大多数操作系统上,这会设置 SO_RCVBUF 套接字选项。
Sourcepub fn recv_buffer_size(&self) -> Result<u32>
pub fn recv_buffer_size(&self) -> Result<u32>
返回该套接字的 TCP 接收缓冲区大小。
在大多数操作系统上,这就是 SO_RCVBUF 套接字选项的值。
请注意,如果此前已在此套接字上调用过 set_recv_buffer_size,则此函数返回的值可能与提供给 set_recv_buffer_size 的参数不同。原因如下:
- Most operating systems have minimum and maximum allowed sizes for the receive buffer, and will clamp the provided value if it is below the minimum or above the maximum. The minimum and maximum buffer sizes are OS-dependent.
- Linux will double the buffer size to account for internal bookkeeping
data, and returns the doubled value from
getsockopt(2). As perman 7 socket:以字节为单位设置或获取最大套接字发送缓冲区。当使用
setsockopt(2)设置该值时,内核会将其加倍(以留出簿记开销的空间),getsockopt(2)返回的是加倍后的值。
Sourcepub fn set_linger(&self, dur: Option<Duration>) -> Result<()>
👎Deprecated: SO_LINGER causes the socket to block the thread on drop
pub fn set_linger(&self, dur: Option<Duration>) -> Result<()>
SO_LINGER causes the socket to block the thread on drop通过设置 SO_LINGER 选项来设置该套接字的 linger 时间。
当流中存在未发送的消息且流被关闭时,此选项控制所采取的操作。如果设置了 SO_LINGER,系统将阻塞当前进程,直到能够传输完数据或时间到期为止。
如果没有指定 SO_LINGER,并且套接字被关闭,系统将以允许进程尽快继续的方式处理该调用。
此选项已弃用,因为在 Tokio 使用的套接字上设置 SO_LINGER 始终是不正确的,因为这样会在关闭套接字时阻塞线程。有关更多详细信息,请参阅:
大量的通信研究都聚焦于
SO_LINGER与非阻塞(O_NONBLOCK)套接字之间的复杂细节。据我了解,最终结论是:不要这样做。请改用shutdown()后接read()收到 EOF 的技术。来自 The ultimate
SO_LINGERpage, or: why is my tcp not reliable
尽管此方法已废弃,但不会从 Tokio 中移除。
请注意,将 SO_LINGER 设为 0 这一特殊情况不会导致阻塞。Tokio 为此提供了 set_zero_linger。
Sourcepub fn set_zero_linger(&self) -> Result<()>
pub fn set_zero_linger(&self) -> Result<()>
通过设置 SO_LINGER 选项,将该套接字的 linger 时间设置为零。
这会在套接字被丢弃或关闭时强制中止连接(“abortive close”)。不同于正常的 TCP 关闭握手(FIN/ACK),会向对端发送 TCP RST(重置)报文段,且套接字会立即丢弃发送缓冲区中尚未发送的任何数据。这样可以防止套接字在关闭后进入 TIME_WAIT 状态。
这是一种破坏性操作。当前由操作系统缓存但尚未发送的任何数据都将丢失。对端很可能会收到“Connection Reset”错误,而不是干净的流结束信号。
有关 SO_LINGER 工作原理的其他详细信息,请参阅 set_linger 的文档。
Sourcepub fn linger(&self) -> Result<Option<Duration>>
pub fn linger(&self) -> Result<Option<Duration>>
通过获取 SO_LINGER 选项来读取此套接字的 linger 时长。
有关此选项的更多信息,请参见 set_zero_linger 和 set_linger。
Sourcepub fn set_nodelay(&self, nodelay: bool) -> Result<()>
pub fn set_nodelay(&self, nodelay: bool) -> Result<()>
设置该套接字上 TCP_NODELAY 选项的值。
如果设置,此选项会禁用 Nagle 算法。也就是说,即使数据量很小,TCP 段也会尽快发送。如果不设置,数据会被缓冲,直到累积到足够的量再发送,从而避免频繁发送小包。
§示例
use tokio::net::TcpSocket;
let socket = TcpSocket::new_v4()?;
socket.set_nodelay(true)?;Sourcepub fn nodelay(&self) -> Result<bool>
pub fn nodelay(&self) -> Result<bool>
获取该套接字上 TCP_NODELAY 选项的值。
有关此选项的更多信息,请参见 set_nodelay。
§示例
use tokio::net::TcpSocket;
let socket = TcpSocket::new_v4()?;
println!("{:?}", socket.nodelay()?);Sourcepub fn tos_v4(&self) -> Result<u32>
pub fn tos_v4(&self) -> Result<u32>
获取该套接字的 IP_TOS 选项值。
有关此选项的更多信息,请参见 set_tos_v4。
Sourcepub fn set_tos_v4(&self, tos: u32) -> Result<()>
pub fn set_tos_v4(&self, tos: u32) -> Result<()>
为该套接字设置 IP_TOS 选项的值。
此值设置了从该套接字发出的每个数据包中使用的服务类型字段。
§Note
- This may not have any effect on IPv6 sockets.
- On Windows,
IP_TOSis only supported on Windows 8+ or Windows Server 2012+.
Sourcepub fn local_addr(&self) -> Result<SocketAddr>
pub fn local_addr(&self) -> Result<SocketAddr>
获取该套接字的本地地址。
如果在 bind 之前调用,则在 Windows 上会失败。
§示例
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.bind(addr)?;
assert_eq!(socket.local_addr().unwrap().to_string(), "127.0.0.1:8080");
let listener = socket.listen(1024)?;
Ok(())
}Sourcepub fn take_error(&self) -> Result<Option<Error>>
pub fn take_error(&self) -> Result<Option<Error>>
返回 SO_ERROR 选项的值。
Sourcepub fn bind(&self, addr: SocketAddr) -> Result<()>
pub fn bind(&self, addr: SocketAddr) -> Result<()>
将套接字绑定到给定地址。
此函数会调用操作系统的 bind(2) 函数。具体行为取决于平台。更多细节请参考目标平台的文档。
§示例
在监听之前绑定一个套接字。
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.bind(addr)?;
let listener = socket.listen(1024)?;
Ok(())
}Sourcepub async fn connect(self, addr: SocketAddr) -> Result<TcpStream>
pub async fn connect(self, addr: SocketAddr) -> Result<TcpStream>
与指定套接字地址的对端建立 TCP 连接。
该 TcpSocket 会被消费。一旦连接建立成功,将返回一个已连接的 TcpStream。如果连接失败,则返回所遇到的错误。
此函数会调用操作系统的 connect(2) 函数。具体行为取决于平台。更多细节请参考目标平台的文档。
§示例
连接到对端。
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
let stream = socket.connect(addr).await?;
Ok(())
}Sourcepub fn listen(self, backlog: u32) -> Result<TcpListener>
pub fn listen(self, backlog: u32) -> Result<TcpListener>
将该套接字转换为 TcpListener。
backlog 定义了在任意时刻由操作系统排队的最大待连接数。连接通过 TcpListener::accept 从队列中移除。当队列已满时,操作系统将开始拒绝新的连接。
此函数会调用操作系统的 listen(2) 函数,将套接字标记为被动套接字。具体行为取决于平台。更多细节请参考目标平台的文档。
§示例
创建一个 TcpListener。
use tokio::net::TcpSocket;
use std::io;
#[tokio::main]
async fn main() -> io::Result<()> {
let addr = "127.0.0.1:8080".parse().unwrap();
let socket = TcpSocket::new_v4()?;
socket.bind(addr)?;
let listener = socket.listen(1024)?;
Ok(())
}Sourcepub fn from_std_stream(std_stream: TcpStream) -> TcpSocket
pub fn from_std_stream(std_stream: TcpStream) -> TcpSocket
将 std::net::TcpStream 转换为 TcpSocket。所提供的套接字必须在调用此函数之前尚未连接。此函数通常与 socket2 等 crate 一起使用,以配置 TcpSocket 上未提供的套接字选项。
§Notes
调用者负责确保套接字处于非阻塞模式。否则,套接字上的所有 I/O 操作都会阻塞线程,从而导致意外行为。可以使用 set_nonblocking 设置非阻塞模式。
§示例
use tokio::net::TcpSocket;
use socket2::{Domain, Socket, Type};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let socket2_socket = Socket::new(Domain::IPV4, Type::STREAM, None)?;
socket2_socket.set_nonblocking(true)?;
let socket = TcpSocket::from_std_stream(socket2_socket.into());
Ok(())
}Trait 实现§
Source§impl AsRawSocket for TcpSocket
Available on docsrs, or Windows only.
impl AsRawSocket for TcpSocket
docsrs, or Windows only.Source§fn as_raw_socket(&self) -> RawSocket
fn as_raw_socket(&self) -> RawSocket
Source§impl AsSocket for TcpSocket
Available on docsrs, or Windows only.
impl AsSocket for TcpSocket
docsrs, or Windows only.Source§fn as_socket(&self) -> BorrowedSocket<'_>
fn as_socket(&self) -> BorrowedSocket<'_>
Source§impl FromRawSocket for TcpSocket
Available on docsrs, or Windows only.
impl FromRawSocket for TcpSocket
docsrs, or Windows only.Source§impl IntoRawSocket for TcpSocket
Available on docsrs, or Windows only.
impl IntoRawSocket for TcpSocket
docsrs, or Windows only.