Nix crate's fork() call

Hi, I'm trying to learn more Rust by writing the examples in Beej's Guide to Network Programming from C to Rust. :blush:

I have this block code (TCP server accepting connections from a client):

    match listener.accept() {
        Ok((mut stream, addr)) => {
            println!("connection accepted: {:?}", addr);
            match fork() {
                Ok(ForkResult::Child) => {
                    stream.write(b"Hello world!")?;
                    stream.shutdown(Shutdown::Both).expect("Child shutdown failed")
                Ok(ForkResult::Parent {child: _, ..}) => {
                    stream.shutdown(Shutdown::Both).expect("Parent shutdown failed")
                Err(_) => {
                    println!("fork() failed")
        Err(e) => println!("attempt from client: {:?} failed", e),

I am using the nix crate to fork() a new process. I was expecting the stream in both the parent block and the child block to be different copies. But, it looks like they are the same. Running the code above, I get the following error when a client connects:

Error: Os { code: 32, kind: BrokenPipe, message: "Broken pipe" }

But if I comment out the stream.shutdown() call in the parent block, then the client can connect and receive the message.

Is this behavior inherent to the Rust language? -OR- is it an implementation specific behavior and I should be asking the folks from nix for clarifications about this?

Shuts down the read, write, or both halves of this connection.

This function will cause all pending and future I/O on the specified portions to return immediately with an appropriate value (see the documentation of Shutdown ).

By forking a process you can't magically duplicate a TCP connection. A TCP connection is uniquely determined by source/destination ip and port. stream.shutdown() sends an RST packet to the system you are connected with closing the connection on both ends.


I see. So is it correct to say that in this context, both the parent and the child processes are sharing the same resource (TCP connection)?


To be honest fork-per-connection is a strategy which was common before we invented the thread. Linux and other OSes invented the thread because the process-per-connection model is too slow for internet scale servers, and just before the millennium we invented the async programming because the thread-per-connection model is too slow for web scale servers, AKA C10K problem.

I'd recommend not to use fork() for concurrency/parallelism, especially for Rust. It would not works well with modern multithreading tools, which is really common in the Rust ecosystem.


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.