Skip to content

Commit

Permalink
Open a final connection to stop the sending side
Browse files Browse the repository at this point in the history
It's a hack maybe, but I really want to avoid the async ecosystem.
  • Loading branch information
ruuda committed Jul 12, 2024
1 parent 3d16a6e commit 88986a7
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 3 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ On the receiving end, suppose we download with 32 TCP connections:

## Known issues

* The sender doesn't exit when it's done.
* It's too spammy.
22 changes: 20 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,11 @@ fn main_send(addr: &str, fnames: &[String]) -> Result<()> {
push_threads.push(push_thread);
}

// If we stopped the listener loop, then the receiver should have signalled
// that it received everything, so all sender threads should have finished.
// For a long transfer, the listener loop exists when the receiver signals
// that it received everything by connecting one final time. But it can also
// happen that we pushed everything before the receiver was even done
// spawning connections, so either way, we need to wait for the push threads
// to finish sending.
for push_thread in push_threads {
push_thread.join().expect("Failed to wait for push thread.");
}
Expand Down Expand Up @@ -431,6 +434,21 @@ fn main_recv(addr: &str, n_conn: &str) -> Result<()> {
pull_thread.join().expect("Failed to join pull thread.")?;
}

// After all pulls are done and the transfer is complete, the sender is
// still stuck in its accept() call listening for potential additional
// readers. One way to get around that is by doing a non-blocking accept,
// but then we either have to busy-wait, or if we add a sleep then we create
// a polling delay. Another way is to make everything async, but then we
// have to add a dependency on the async ecosystem and pull in 100s of
// crates, and create gigabytes of build artifacts, just to do a clean exit.
// So as a hack, just connect one more time to wake up the sender's accept()
// loop. It will conclude there is nothing to send and then exit.
match TcpStream::connect(addr) {
Ok(stream) => std::mem::drop(stream),
// Too bad if we can't wake up the sender, but it's not our problem.
Err(_) => {}
}

writer_thread.join().expect("Failed to join writer thread.");

Ok(())
Expand Down

0 comments on commit 88986a7

Please sign in to comment.