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: after call of {TCP,UDP,IP,Unix}Conn/{TCP,Unix}Listener.File(), the deadline will be ineffective #21862

Closed
goosman-lei opened this issue Sep 13, 2017 · 6 comments

Comments

@goosman-lei
Copy link

if err = syscall.SetNonblock(ns, false); err != nil {

in the under demo code:
the first goroutine, listener is not call (*net.TCPListener).File(), it timeout with setDeadline() works fine

the second goroutine, listener call (*net.TCPListener).File(), after that, the timeout don't work

the third goroutine, listener call (*net.TCPListener).File(), but then set it to non-blocking mode, timeout works fine too

package main

import (
    "fmt"
    "net"
    "sync"
    "syscall"
    "time"
)

func main() {
    wg := new(sync.WaitGroup)
    wg.Add(2)

    go func() {
        addr, _ := net.ResolveTCPAddr("tcp", ":2020")
        l, _ := net.ListenTCP("tcp", addr)
        for {
            l.SetDeadline(time.Now().Add(time.Second))
            c, err := l.AcceptTCP()
            if err != nil {
                if nErr, ok := err.(net.Error); ok && nErr.Timeout() {
                    fmt.Printf("server 1 timeout at: %s\n", time.Now())
                    continue
                }   
                fmt.Printf("server 1 error: %s\n", err)
                break
            }   
            fmt.Printf("server 1 accept from: %s %s\n", c.RemoteAddr().String(), time.Now())
        }   
        wg.Done()
    }() 
    go func() {
        addr, _ := net.ResolveTCPAddr("tcp", ":2021")
        l, _ := net.ListenTCP("tcp", addr)
        l.File()
        for {
            l.SetDeadline(time.Now().Add(time.Second))
            c, err := l.AcceptTCP()
            if err != nil {
                if nErr, ok := err.(net.Error); ok && nErr.Timeout() {
                    fmt.Printf("server 2 timeout at: %s\n", time.Now())
                    continue
                }   
                fmt.Printf("server 2 error: %s\n", err)
                break
            }   
            fmt.Printf("server 2 accept from: %s %s\n", c.RemoteAddr().String(), time.Now())
        }   
        wg.Done()
    }() 
    go func() {
        addr, _ := net.ResolveTCPAddr("tcp", ":2022")
        l, _ := net.ListenTCP("tcp", addr)
        f, _ := l.File()
        syscall.SetNonblock(int(f.Fd()), true)
        for {
            l.SetDeadline(time.Now().Add(time.Second))
            c, err := l.AcceptTCP()
            if err != nil {
                if nErr, ok := err.(net.Error); ok && nErr.Timeout() {
                    fmt.Printf("server 3 timeout at: %s\n", time.Now())
                    continue
                }   
                fmt.Printf("server 3 error: %s\n", err)
                break
            }   
            fmt.Printf("server 3 accept from: %s %s\n", c.RemoteAddr().String(), time.Now())
        }   
        wg.Done()
    }() 

    wg.Wait()
}
@ianlancetaylor ianlancetaylor changed the title After call of (*net.TCPListener).File(), the listener's deadline will ineffective net: after call of (*net.TCPListener).File(), the listener's deadline will ineffective Sep 13, 2017
@ianlancetaylor
Copy link
Contributor

I assume you are running on a Unix system.

I don't see any way to fix this. Do you have any suggestions?

@goosman-lei
Copy link
Author

I don't understand why here set fd to blocking mode. .
In my opinion, whether set into blocking mode, should taken the control to user programmer

@bradfitz
Copy link
Contributor

Is this fixed by (*TCPListener) SyscallConn() (syscall.RawConn, error) in Go 1.10?

https://tip.golang.org/pkg/net/#TCPListener.SyscallConn

@bradfitz bradfitz added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Nov 28, 2017
@crvv
Copy link
Contributor

crvv commented Nov 30, 2017

Is this fixed by (*TCPListener) SyscallConn() (syscall.RawConn, error) in Go 1.10?

The issue is the method *(net.TCPListener).File makes the deadline ineffective.
It can't be fixed by adding a new method. The method File() can still break the deadline.

SyscallConn can give me the fd without making the deadline ineffective.
So I think it's good enough if the behavior is documented clearly.

package main

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

func main() {
        addr, _ := net.ResolveTCPAddr("tcp", ":2022")
        l, _ := net.ListenTCP("tcp", addr)
        sc, _ := l.SyscallConn()
        sc.Control(func(fd uintptr) { println(fd) })
        for {
                l.SetDeadline(time.Now().Add(time.Second))
                c, err := l.AcceptTCP()
                if err != nil {
                        if nErr, ok := err.(net.Error); ok && nErr.Timeout() {
                                fmt.Printf("server 3 timeout at: %s\n", time.Now())
                                continue
                        }
                        fmt.Printf("server 3 error: %s\n", err)
                        break
                }
                fmt.Printf("server 3 accept from: %s %s\n", c.RemoteAddr().String(), time.Now())
        }
}

@mikioh mikioh changed the title net: after call of (*net.TCPListener).File(), the listener's deadline will ineffective net: after call of {TCP,UDP,IP,Unix}Conn/{TCP,Unix}Listener.File(), the deadline will be ineffective Nov 30, 2017
@gopherbot
Copy link

Change https://golang.org/cl/82915 mentions this issue: net: calling File disables the SetDeadline methods

@mikioh
Copy link
Contributor

mikioh commented Apr 20, 2018

Also see #24942.

@mikioh mikioh removed the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Apr 20, 2018
@golang golang locked and limited conversation to collaborators Apr 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants