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: TCPConn.CloseRead() will not cause the net.TCPConn.Read() return on windows but it can cause return on linux #41002

Open
chenjie199234 opened this issue Aug 24, 2020 · 14 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Milestone

Comments

@chenjie199234
Copy link

same code has different performace on windows and linux
start the server first and then start the client
on linux:the server will panic
on windows:the server will not panic
golang version 1.14.4

server

package main

import (
	"net"
	"time"
)

func main() {
	addr, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:9234")
	l, _ := net.ListenTCP("tcp", addr)
	c, _ := l.AcceptTCP()
	go func() {
		time.Sleep(time.Second)
		c.CloseRead()
		println("close read success")
	}()
	buf := make([]byte, 1024)
	n, e := c.Read(buf)
	if e != nil {
		panic(e)
	}
	print(buf[:n])
}

client

package main

import (
	"net"
	"time"
)

func main() {
	addr, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:9234")
	c, _ := net.DialTCP("tcp", nil, addr)
	time.Sleep(time.Minute)
	c.Write([]byte("123"))
}
@davecheney
Copy link
Contributor

What’s is the value of n returned on windows?

@chenjie199234
Copy link
Author

@davecheney
企业微信截图_15982716021496
the return n is 3

@davecheney
Copy link
Contributor

what is the value of n on the linux system?

@chenjie199234
Copy link
Author

chenjie199234 commented Aug 24, 2020

@davecheney on linux,when call closeread,the read will return with an error

@davecheney
Copy link
Contributor

Read returns two values, a count of the number of bytes and an error. You’ve identified that the error is not nil, what was the count of the number of bytes read?

@chenjie199234
Copy link
Author

@davecheney the count of the number is 0,the client is sleep on time.Sleep(time.Miunte) the client didn't send any thing

@davecheney
Copy link
Contributor

Thank you for explaining. I’m trying to understand the Issue you are reporting. It is not that the code panics under linux and not under windows because the panic is in your code, not go.

The difference appears to be that under linux when you call CloseRead in another goroutine the Goroutine waiting in Read receives 3, nil on windows and 0, (some non nil error) on linux. Is that a correct summary?

@chenjie199234
Copy link
Author

@davecheney the summary is:

when a connect is block on Read()

on linux:net.TCPConn.CloseRead() will cause the block Read() return with 0 and error
on window:net.TCPConn.CloseRead() will not cause the block Read() return,the connect is still block on Read(),when a client send a message after server CloseRead(),the server still can read the message.

run the code by your self or show it to other developers,they will know what happened

@davecheney
Copy link
Contributor

I’m sorry I don’t have access to a windows computer.

@davecheney
Copy link
Contributor

@chenjie199234 can you please try this self contained program

(~/src) % go run test.go
close read success
0, [], EOF
(~/src) % cat test.go
package main

import (
        "fmt"
        "log"
        "net"
        "time"
)

func main() {
        addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:9234")
        check(err)
        l, err := net.ListenTCP("tcp", addr)
        check(err)
        go func() {
                c, err := net.DialTCP("tcp", nil, addr)
                check(err)
                time.Sleep(time.Minute)
                c.Write([]byte("123"))
        }()
        c, err := l.AcceptTCP()
        check(err)
        go func() {
                time.Sleep(time.Second)
                c.CloseRead()
                println("close read success")
        }()
        buf := make([]byte, 1024)
        n, err := c.Read(buf)
        buf = buf[:n]
        fmt.Printf("%v, %v, %v\n", n, buf, err)
}

func check(err error) {
        if err != nil {
                log.Fatal(err)
        }
}

@davecheney davecheney added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Aug 25, 2020
@chenjie199234
Copy link
Author

chenjie199234 commented Aug 26, 2020

@davecheney on windows return this:between the first line output and second line output,the program will block 1 minute
企业微信截图_15984138123502

@davecheney
Copy link
Contributor

@chenjie199234 thank you for confirming. I'm going to hand this over to the windows experts now. /cc @alexbrainman

@davecheney davecheney added NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. and removed WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. labels Aug 26, 2020
@alexbrainman
Copy link
Member

Thank you @davecheney for helping here. I can reproduce @chenjie199234 result on Windows, but I am not convinced there is a problem here.

We do

client Read
client CloseRead
server Write

in that order.

It appears that CloseRead behaves differently on Linux and Windows.

On Linux it makes Read return EOF, and (I assume) makes Write fail.

On Windows it makes Read return sent bytes, and (I assume) makes Write succeed.

I say either scenario is fine. There is a race here between Read and CloseRead, and result here depends on network stack implementation.

In my view, CloseRead cannot be used for anything useful. Only Close and CloseWrite are useful. Both ends of the connection should keep reading from the connection until EOF, if you do not want to loose some data.

Alex

@networkimprov
Copy link

cc @ianlancetaylor @bcmills

@seankhliao seankhliao changed the title net.TCPConn.CloseRead() will not cause the net.TCPConn.Read() return on windows but it can cause return on linux net: TCPConn.CloseRead() will not cause the net.TCPConn.Read() return on windows but it can cause return on linux Jun 18, 2021
@seankhliao seankhliao added this to the Unplanned milestone Aug 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Projects
None yet
Development

No branches or pull requests

5 participants