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

@goosman-lei goosman-lei commented Sep 13, 2017

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

This comment has been minimized.

Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Sep 13, 2017

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

This comment has been minimized.

Copy link
Author

@goosman-lei goosman-lei commented Sep 19, 2017

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

This comment has been minimized.

Copy link
Contributor

@bradfitz bradfitz commented Nov 28, 2017

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

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

@crvv

This comment has been minimized.

Copy link
Contributor

@crvv 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

This comment has been minimized.

Copy link

@gopherbot gopherbot commented Dec 8, 2017

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

@gopherbot gopherbot closed this in a941028 Dec 8, 2017
@mikioh

This comment has been minimized.

Copy link
Contributor

@mikioh mikioh commented Apr 20, 2018

Also see #24942.

@mikioh mikioh removed the WaitingForInfo 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
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.