pub struct TcpListener<M = Local>where
M: Mode,{ /* private fields */ }Expand description
A TCP socket server, listening for connections.
Create a listener with TcpListener::bind. Then call accept to take
one connection, or incoming for a stream of connections. Each
connection is a TcpStream. The listener is the async counterpart of
std::net::TcpListener: waiting for a connection lets other tasks run instead of blocking the
thread.
The listener runs on the runtime passed to its constructor, and so do the streams it accepts.
Its type carries that runtime’s flavour, as the module documentation explains: a
TcpListener<Local> (the default) stays on the thread that made it, and a TcpListener<Shared>
can be sent to and used from any thread.
Any number of tasks can wait in accept at once through a reference to
the listener, and each connection goes to one of them. Only one task at a time can wait for the
next item of an Incoming stream, counting all the streams of the listener. Tasks waiting in
accept do not count.
§Example
A listener accepts a connection and reads a greeting from it. A client makes the connection and sends the greeting.
use std::net::Ipv4Addr;
use futures::{AsyncReadExt, AsyncWriteExt};
use zruntime::{
LocalRuntime,
net::{TcpListener, TcpStream},
};
let runtime = LocalRuntime::new()?;
// Port `0` lets the system pick a free port.
let listener = TcpListener::bind(&runtime, (Ipv4Addr::LOCALHOST, 0))?;
let address = listener.local_addr()?;
runtime.block_on(async {
let mut client = TcpStream::connect(&runtime, address).await?;
client.write_all(b"hello").await?;
let (mut server, peer) = listener.accept().await?;
let mut greeting = [0; 5];
server.read_exact(&mut greeting).await?;
assert_eq!(&greeting, b"hello");
assert_eq!(peer, client.local_addr()?);
})?;Implementations§
Source§impl<M> TcpListener<M>where
M: Mode,
impl<M> TcpListener<M>where
M: Mode,
Sourcepub fn bind<A>(runtime: &Runtime<M>, addr: A) -> Result<Self>where
A: Into<SocketAddr>,
pub fn bind<A>(runtime: &Runtime<M>, addr: A) -> Result<Self>where
A: Into<SocketAddr>,
Creates a listener bound to addr, on runtime.
addr is a socket address: a SocketAddr, or anything that converts into one, such as a
pair of an Ipv4Addr and a port. It is never a host name; the
module documentation explains what to do instead. Binding to port 0 lets the
system pick a free port, which local_addr returns.
The listener is bound and listening when this returns.
§Errors
Fails if the socket cannot be bound to addr, or for the reasons
from_std fails.
On wasm32-wasip1 it always fails with Unsupported: that
target cannot create a socket (see the module documentation).
from_std takes a listener that the host handed in instead.
Sourcepub fn from_std(runtime: &Runtime<M>, listener: TcpListener) -> Result<Self>
pub fn from_std(runtime: &Runtime<M>, listener: TcpListener) -> Result<Self>
Creates a listener on runtime from a std listener.
listener is switched to non-blocking mode, as every listener of this type is. On unix, the
mode belongs to the open socket, so a duplicate made with
try_clone is switched too. An accept on that
duplicate then fails with WouldBlock instead of waiting.
§Errors
Fails if switching to non-blocking mode fails, or if the runtime cannot start watching the socket. On Windows a runtime watches a limited number of sockets; see the module documentation.
Sourcepub async fn accept(&self) -> Result<(TcpStream<M>, SocketAddr)>
pub async fn accept(&self) -> Result<(TcpStream<M>, SocketAddr)>
Waits for a connection to this listener, and accepts it.
Returns the stream of the connection and the address of the peer that made it. The stream runs on the listener’s runtime and is in non-blocking mode.
§Errors
Returns the error of the accept.
Some errors leave the connection queued, for example running out of file descriptors
(EMFILE) on Linux and the BSDs. The next call then fails again at once, and so on until
the connection leaves the queue, so a loop that keeps accepting after an error spins the
thread. Back off after an error, for example with Runtime::sleep. On Apple’s platforms
an accept that finds no descriptor left closes the connection instead: the error does not
repeat, but the connection is lost.
On Windows a runtime watches a limited number of sockets (see the module documentation). An accept that would exceed the limit fails, and the connection it took off the queue is closed. Its peer sees the connection end.
§Cancel safety
Dropping the future before it completes gives up the wait. No connection is lost: a connection that arrives meanwhile stays queued for the next call.
Sourcepub fn incoming(&self) -> Incoming<'_, M>
pub fn incoming(&self) -> Incoming<'_, M>
Returns a stream of the connections made to this listener.
Each item is the TcpStream of a connection, accepted as accept
accepts it, or the error of a failed accept. See Incoming for how errors and waiting
tasks behave.
§Example
The stream yields the first two connections made to a listener, in the order they were made.
use std::net::Ipv4Addr;
use futures::StreamExt;
use zruntime::{
LocalRuntime,
net::{TcpListener, TcpStream},
};
let runtime = LocalRuntime::new()?;
let listener = TcpListener::bind(&runtime, (Ipv4Addr::LOCALHOST, 0))?;
let address = listener.local_addr()?;
runtime.block_on(async {
let first = TcpStream::connect(&runtime, address).await?;
let second = TcpStream::connect(&runtime, address).await?;
let mut incoming = listener.incoming();
let first_accepted = incoming.next().await.expect("the stream never ends")?;
let second_accepted = incoming.next().await.expect("the stream never ends")?;
assert_eq!(first_accepted.peer_addr()?, first.local_addr()?);
assert_eq!(second_accepted.peer_addr()?, second.local_addr()?);
})?;Sourcepub fn local_addr(&self) -> Result<SocketAddr>
pub fn local_addr(&self) -> Result<SocketAddr>
The socket address this listener is bound to.
After binding to port 0, this returns the port the system picked.