Mtcp - TcpListener/TcpStream *with* timeout/cancellation support

mtcp – Metal TCP

mtcp provides a "blocking" TcpListener and TcpStream with timeout and cancellation support.

This is pretty much a drop-in replacement for std::net::{TcpListener, TcpStream}, but with an additional timeout parameter in the "blocking" functions. Also, a Canceller can be used to abort the "pending" operation immediately, e.g. from another thread or from the Ctrl+C handler.

The "blocking" operations are emulated via mio, but you won't have to deal with mio directly at all.

@crates.io:
https://crates.io/crates/mtcp-rs

API Documentation:

Examples:

Repository:

License:
The Unlicense / Public Domain


Rusty HTTP Server:

Simple and multi-threaded HTTP server, based based on mtcp-rs.

I'd suggest you to host this on a GitHub repository and maybe publish it on crates.io to help users reuse your crate.

One concern about code is that you should let users instantiate Rc<TcpManager> instead of forcing one instance by threads. In current implementation, once you call cancel() you can't use the TcpManager from this thread anymore.

Cancelling doesn't always mean you want to exit the process, maybe the network communication is only part of the whole process and we want to be able to abort it before timeout expires but this network communication could happen again later.

Why not let user create their Rc<TcpManager> ?

Thanks for response!

I'd suggest you to host this on a GitHub repository and maybe publish it on crates.io to help users reuse your crate.

Okay, I will look into this soon.

One concern about code is that you should let users instantiate Rc<TcpManager> instead of forcing one instance by threads. In current implementation, once you call cancel() you can't use the TcpManager from this thread anymore.

Cancelling doesn't always mean you want to exit the process, maybe the network communication is only part of the whole process and we want to be able to abort it before timeout expires but this network communication could happen again later.

Why not let user create their Rc<TcpManager> ?

You are right. In the latest version I have made it possible to create TcpManager separately.

Also, I have added functions to "restart" the TcpManager.

1 Like

I'd suggest you to host this on a GitHub repository and maybe publish it on crates.io to help users reuse your crate.

Okay, I have finally uploaded my project to crates.io today :sunglasses:
https://crates.io/crates/mtcp-rs

Version 0.1.3 has been released.

This release uses lazy_rc and contains various fixes and improvements.

Rusty HTTP Server :partying_face:

Simple HTTP server implemented purely in Rust, heavily based on mtcp-rs

pub fn bind(manager: &Rc<TcpManager>, addr: SocketAddr) -> IoResult<Self> {
    let manager = manager.clone();
    //...
}

It's typically better to take owned objects directly instead of cloning a reference because this allows the consumer of the interface to use a preexisting owned object.

Beware that TcpManager is a "shared" instance (shared between all your TcpListener and TcpStream instances) and is therefore wrapped in an Rc<T>. So, we are taking a reference to an Rc<T> here, and only the Rc<T> will be cloned, not the "inner" TcpManager – thus incrementing the reference counter.

I think this should be okay? :thinking:

I mean, the alternative would be to take a Rc<TcpManager> by-value rather than by-reference, and therefore require the caller to perform the clone() of the Rc<T> to increment the reference count.

I think I prefer the current way... :sweat_smile:

I mean, the alternative would be to take a Rc<TcpManager> by-value rather than by-reference, and therefore require the caller to perform the clone() of the Rc<T> to increment the reference count.

This is exactly what I meant and what is considered the idiomatic way.

1 Like

I understand this for the "general" case, where you'd want to have the choice to either "move" your owned object are pass a clone(). But in case of a "shared" ref-counted Rc<T>, it would only mean that we'd have to do the necessary clone() at every call site, rather than in just one place... :thinking:

1 Like

It is ofc a question of preference and imo the scale does not tilt heavily in either direction for shared objects like Rc. Personally, I find the by-value variant to be semantically cleaner because it signifies that it always needs it's own object. A by-reference call weakly implies that the Rc is only cloned sometimes.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.