Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: can {Conn,PacketConn}.Close block? #18187

Open
dsnet opened this issue Dec 3, 2016 · 10 comments
Open

net: can {Conn,PacketConn}.Close block? #18187

dsnet opened this issue Dec 3, 2016 · 10 comments
Labels
Documentation NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@dsnet
Copy link
Member

dsnet commented Dec 3, 2016

The documentation for net.Conn.Close is:

Close closes the connection. Any blocked Read or Write operations will be unblocked and return errors.

However, it does not mention anything about whether Close itself can block.

Some net.Conn implementations have an implicit write buffer. Thus, when Close is called, it still needs to flush the buffer before returning. This means that Close is effectively an operation that involves IO. Since it involves IO, this means that Close may have to wait until the recipient acknowledges the incoming data (which could potentially be forever if the receiver's read buffer is full).

If we extend the documentation for net.Conn.Close, would the following be reasonable?

Close closes the connection. Any blocked Read or Write operations will be unblocked and return errors. Close itself may block while it is flushing any internal write buffers, but must return an error and terminate the connection when a previously set write deadline is exceeded.

\cc @bradfitz @mikioh

@dsnet dsnet added Documentation NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels Dec 3, 2016
@dsnet dsnet added this to the Go1.8 milestone Dec 3, 2016
@dsnet
Copy link
Member Author

dsnet commented Dec 3, 2016

For reasons that I don't understand, I'm not able to get TCPConn.Close to block even when I write as much data on one endpoint while nothing is reading on the other endpoint.

In other implementations I'm looking at, it is impossible to get Close to be non-blocking since the underlying layers provide no control over flushing and have implicit write buffers built into them.

@mikioh mikioh changed the title net: can Conn.Close block? net: can {Conn,PacketConn}.Close block? Dec 4, 2016
@mikioh
Copy link
Contributor

mikioh commented Dec 4, 2016

#10527 is for Listener.Close.

@bradfitz
Copy link
Contributor

bradfitz commented Dec 4, 2016

Yes, we've had to make changes to the net/http package in the past due to net.Conn implementations blocking on Close. If it's an interface, anything can happen. It's fine to document that it may block, if it's not overly wordy.

@bradfitz bradfitz added NeedsFix The path to resolution is known, but the work has not been done. and removed NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. labels Dec 4, 2016
@bradfitz bradfitz modified the milestones: Go1.9Maybe, Go1.8, Go1.8Maybe Dec 5, 2016
@bradfitz bradfitz modified the milestones: Go1.9, Go1.8Maybe Dec 15, 2016
@bradfitz bradfitz modified the milestones: Go1.10, Go1.9 Jun 26, 2017
@dsnet dsnet modified the milestones: Go1.10, Unplanned Nov 10, 2017
@dsnet dsnet removed their assignment Dec 6, 2017
@dunjut
Copy link

dunjut commented Mar 13, 2019

Is it possible or not that a TCPConn.Close() may block?

@arkaml
Copy link

arkaml commented Mar 29, 2019

Scenario:

I have a "high concurrency" client on a payment processing solution under production which when it detects the connection might be dead (multiple concurrent errors on non blocking read() or write() calls) it enters a reconnect loop to different secondary backup servers until it gets able to keep processing transactions.

A couple of days ago the single threaded component handling de TCP socket I/O hanged out, watching the source code for hours i couldn't find a single blocking condition, suddenly i realized, might be Close() blocking?

Why i perform the Close call? because the underlying protocol (old credit cards processing protocol implementation) would send back responses on any opened detected socket, no matter in which socket it received the request.. so if i don't perform the correct TCP connection closure before establishing a new TCP connection i might get into an scenario were the responses for the requests sent through the new established socket might start getting back in the original connection once the networking issue gets solved.

So, the question made by @dunjut is really critical in my scenario. Is Close() candidate to block? I was really not expecting this condition to happen :(

@JFR-Adroll
Copy link

You can have a blocking conn.Close by doing something like:

...
reader := bufio.NewReader(conn)
go io.ReadFull(reader, buf)
conn.Close()

@Windsooon
Copy link

@dsnet Did you create a PR for it?

@chengxuncc
Copy link

That's it, I call it a day. Can we fix it?

@chengxuncc
Copy link

I finally solved it, thanks to https://stackoverflow.com/questions/28967701/golang-tcp-socket-cant-close-after-get-file, call conn.CloseRead() before calling conn.Close().

func Close(conn io.Closer) error {
	type ReadCloser interface {
		CloseRead() error
	}
	var errs []error
	if closer, ok := conn.(ReadCloser); ok {
		errs = append(errs, closer.CloseRead())
	}
	errs = append(errs, conn.Close())
	for _, err := range errs {
		if err != nil {
			return err
		}
	}
	return nil
}

@davecheney
Copy link
Contributor

Can this issue be closed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

9 participants