跳到主要内容

TcpSocket

搜索

结构体 TcpSocket 

Source
pub struct TcpSocket { /* private fields */ }
展开描述

尚未转换为 TcpStreamTcpListener 的 TCP 套接字。

TcpSocket 包装了一个操作系统套接字,使调用者能够在建立 TCP 连接或接受传入连接之前配置套接字。调用者可以设置套接字选项,并使用套接字地址显式绑定套接字。

TcpSocket 值被丢弃时,底层套接字将被关闭。

仅当 TcpStream::connectTcpListener::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

Source

pub fn new_v4() -> Result<TcpSocket>

创建一个配置为 IPv4 的新套接字。

使用 AF_INETSOCK_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(())
}
Source

pub fn new_v6() -> Result<TcpSocket>

创建一个配置为 IPv6 的新套接字。

使用 AF_INET6SOCK_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(())
}
Source

pub fn set_keepalive(&self, keepalive: bool) -> Result<()>

为该套接字设置 SO_KEEPALIVE 选项的值。

Source

pub fn keepalive(&self) -> Result<bool>

获取该套接字上 SO_KEEPALIVE 选项的值。

Source

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(())
}
Source

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(())
}
Source

pub fn set_send_buffer_size(&self, size: u32) -> Result<()>

为该套接字设置 TCP 发送缓冲区的大小。

在大多数操作系统上,这会设置 SO_SNDBUF 套接字选项。

Source

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 per man 7 socket:

    以字节为单位设置或获取最大套接字发送缓冲区。当使用 setsockopt(2) 设置该值时,内核会将其加倍(以留出簿记开销的空间),getsockopt(2) 返回的是加倍后的值。

Source

pub fn set_recv_buffer_size(&self, size: u32) -> Result<()>

为该套接字设置 TCP 接收缓冲区的大小。

在大多数操作系统上,这会设置 SO_RCVBUF 套接字选项。

Source

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 per man 7 socket:

    以字节为单位设置或获取最大套接字发送缓冲区。当使用 setsockopt(2) 设置该值时,内核会将其加倍(以留出簿记开销的空间),getsockopt(2) 返回的是加倍后的值。

Source

pub fn set_linger(&self, dur: Option<Duration>) -> Result<()>

👎Deprecated: 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_LINGER page, or: why is my tcp not reliable

尽管此方法已废弃,但不会从 Tokio 中移除。

请注意,将 SO_LINGER 设为 0 这一特殊情况不会导致阻塞。Tokio 为此提供了 set_zero_linger

Source

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 的文档。

Source

pub fn linger(&self) -> Result<Option<Duration>>

通过获取 SO_LINGER 选项来读取此套接字的 linger 时长。

有关此选项的更多信息,请参见 set_zero_lingerset_linger

Source

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)?;
Source

pub fn nodelay(&self) -> Result<bool>

获取该套接字上 TCP_NODELAY 选项的值。

有关此选项的更多信息,请参见 set_nodelay

§示例
use tokio::net::TcpSocket;

let socket = TcpSocket::new_v4()?;

println!("{:?}", socket.nodelay()?);
Source

pub fn tos_v4(&self) -> Result<u32>

获取该套接字的 IP_TOS 选项值。

有关此选项的更多信息,请参见 set_tos_v4

Source

pub fn set_tos_v4(&self, tos: u32) -> Result<()>

为该套接字设置 IP_TOS 选项的值。

此值设置了从该套接字发出的每个数据包中使用的服务类型字段。

§Note
Source

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(())
}
Source

pub fn take_error(&self) -> Result<Option<Error>>

返回 SO_ERROR 选项的值。

Source

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(())
}
Source

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(())
}
Source

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(())
}
Source

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.
Source§

fn as_raw_socket(&self) -> RawSocket

Extracts the raw socket. 更多信息
Source§

impl AsSocket for TcpSocket

Available on docsrs, or Windows only.
Source§

fn as_socket(&self) -> BorrowedSocket<'_>

借用此套接字。
Source§

impl Debug for TcpSocket

Source§

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result

使用给定的格式化器格式化此值。 更多信息
Source§

impl FromRawSocket for TcpSocket

Available on docsrs, or Windows only.
Source§

unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket

RawSocket 转换为 TcpStream

§Notes

调用者负责确保套接字处于非阻塞模式。

Source§

impl IntoRawSocket for TcpSocket

Available on docsrs, or Windows only.
Source§

fn into_raw_socket(self) -> RawSocket

Consumes this object, returning the raw underlying socket. 更多信息

自动 Trait 实现§

Blanket 实现§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. 更多信息
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. 更多信息
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. 更多信息
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

原样返回传入的参数。

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

调用 U::from(self)

也就是说,此转换的具体行为取决于 From<T> for U 的实现方式。

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

转换出错时返回的类型。
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

转换出错时返回的类型。
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。