generated from tipragot/rust
Simple non-blocking tcp connection abstraction #13
|
@ -2,9 +2,48 @@
|
|||
|
||||
use std::collections::LinkedList;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::net::{TcpStream, ToSocketAddrs};
|
||||
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
|
||||
|
||||
/// A non-blocking tcp connection.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use bevnet::{Connection, Listener};
|
||||
///
|
||||
/// # fn main() -> io::Result<()> {
|
||||
/// let listener = Listener::bind("127.0.0.1:23732")?;
|
||||
/// let mut connection = Connection::connect("127.0.0.1:23732")?;
|
||||
///
|
||||
/// // The accept operation is not blocking. So we need to loop here.
|
||||
/// let mut server_connection;
|
||||
/// loop {
|
||||
/// if let Some(new_connection) = listener.accept()? {
|
||||
/// server_connection = new_connection;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // We don't need to loop here because the send operation just appends to the send buffer.
|
||||
/// connection.send(b"Hello, world!")?;
|
||||
///
|
||||
/// // To be sure the message has been sent, we need to update the connection.
|
||||
/// while !connection.update()? {
|
||||
/// // Wait until the connection is updated.
|
||||
/// }
|
||||
///
|
||||
/// // The receive operation is not blocking. So we need to loop here.
|
||||
/// loop {
|
||||
/// if let Some(message) = server_connection.receive()? {
|
||||
/// assert_eq!(message, b"Hello, world!");
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Connection {
|
||||
/// The underlying [TcpStream] used for the connection.
|
||||
stream: TcpStream,
|
||||
|
@ -49,8 +88,11 @@ impl Connection {
|
|||
|
||||
/// Sends a message over the connection.
|
||||
///
|
||||
/// Returns `true` if the message has been sent directly and `false`
|
||||
/// if the message is still in the send queue.
|
||||
///
|
||||
/// This function is not blocking.
|
||||
pub fn send(&mut self, message: &[u8]) -> io::Result<()> {
|
||||
pub fn send(&mut self, message: &[u8]) -> io::Result<bool> {
|
||||
// Get the length of the message as a u16.
|
||||
let message_len: u16 = match message.len().try_into() {
|
||||
Ok(len) => len,
|
||||
|
@ -75,9 +117,11 @@ impl Connection {
|
|||
/// Updates the connection.
|
||||
///
|
||||
/// This function sends any pending messages that have not been sent yet.
|
||||
/// It returns `true` if there is no remaining data to send after updating
|
||||
/// the connection and `false` otherwise.
|
||||
///
|
||||
/// This function is not blocking.
|
||||
pub fn update(&mut self) -> io::Result<()> {
|
||||
pub fn update(&mut self) -> io::Result<bool> {
|
||||
// Looping over the send buffers.
|
||||
while let Some((offset, buffer)) = self.send_buffers.front_mut() {
|
||||
// Writing the buffer to the stream.
|
||||
|
@ -95,7 +139,7 @@ impl Connection {
|
|||
}
|
||||
|
||||
// Returning success.
|
||||
Ok(())
|
||||
Ok(self.send_buffers.is_empty())
|
||||
}
|
||||
|
||||
/// Receives a byte block from the connection.
|
||||
|
@ -177,3 +221,48 @@ impl Connection {
|
|||
Ok(Some(&self.receive_buffer[..message_len as usize]))
|
||||
}
|
||||
}
|
||||
|
||||
/// A non-blocking tcp listener.
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io;
|
||||
///
|
||||
/// use bevnet::{Connection, Listener};
|
||||
///
|
||||
/// # fn main() -> io::Result<()> {
|
||||
/// let listener = Listener::bind("127.0.0.1:23732")?;
|
||||
/// let mut connection = Connection::connect("127.0.0.1:23732")?;
|
||||
///
|
||||
/// // The accept operation is not blocking. So we need to loop here.
|
||||
/// let mut server_connection;
|
||||
/// loop {
|
||||
/// if let Some(new_connection) = listener.accept()? {
|
||||
/// server_connection = new_connection;
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Listener(TcpListener);
|
||||
|
||||
impl Listener {
|
||||
/// Creates a new listener.
|
||||
pub fn bind(addr: impl ToSocketAddrs) -> io::Result<Listener> {
|
||||
let listener = TcpListener::bind(addr)?;
|
||||
listener.set_nonblocking(true)?;
|
||||
Ok(Listener(listener))
|
||||
}
|
||||
|
||||
/// Accepts a new [Connection].
|
||||
///
|
||||
/// This function is not blocking.
|
||||
pub fn accept(&self) -> io::Result<Option<Connection>> {
|
||||
match self.0.accept() {
|
||||
Ok((stream, _)) => Connection::new(stream).map(Some),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
|
||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue