panjf2000 / gnet

🚀 gnet is a high-performance, lightweight, non-blocking, event-driven networking framework written in pure Go.
https://gnet.host
Apache License 2.0
9.7k stars 1.04k forks source link

[Bug]: GNet对于accpet的到的socket没有应用用户的设置 #478

Closed CloudGuan closed 1 year ago

CloudGuan commented 1 year ago

Actions I've taken before I'm here

What happened?

在linux系上,用户初始化gnet时,如果配置了socket相关配置,如:接受缓冲区长度,nodely, 关闭timewait等设置 在accept之后,是否应该对于新的文件描述服也要应用对应设置? 代码如下:

// 用户设置
err := gnet.Serve(gl.sEH, protoAddr, gnet.WithReuseAddr(true), gnet.WithTCPKeepAlive(0),
          gnet.WithTCPNoDelay(gnet.TCPNoDelay), gnet.WithSocketRecvBuffer(gl.socketBufferSize),
          gnet.WithSocketSendBuffer(gl.socketBufferSize),
)

accept 代码

func (svr *server) accept(fd int, _ netpoll.IOEvent) error {
    nfd, sa, err := unix.Accept(fd)
    if err != nil {
        if err == unix.EAGAIN || err == unix.ECONNABORTED {
            return nil
        }
        svr.opts.Logger.Errorf("Accept() fails due to error: %v", err)
        return errors.ErrAcceptSocket
    }
    if err = os.NewSyscallError("fcntl nonblock", unix.SetNonblock(nfd, true)); err != nil {
        return err
    }

    remoteAddr := socket.SockaddrToTCPOrUnixAddr(sa)
    if svr.opts.TCPKeepAlive > 0 && svr.ln.network == "tcp" {
        err = socket.SetKeepAlive(nfd, int(svr.opts.TCPKeepAlive/time.Second))
        logging.Error(err)
    }

    el := svr.lb.next(remoteAddr)
    c := newTCPConn(nfd, el, sa, svr.opts.Codec, el.ln.addr, remoteAddr)

    err = el.poller.UrgentTrigger(el.register, c)
    if err != nil {
        _ = unix.Close(nfd)
        c.releaseTCP()
    }
    return nil
}

Major version of gnet

v1

Specific version of gnet

v1.6.7

Operating system

Linux

Relevant log output

Code snippets (optional)

建议是否可以修改为这样,我认为用户的配置应该对于accept到的socket也要生效

func (svr *server) accept(fd int, _ netpoll.IOEvent) error {
    nfd, sa, err := unix.Accept(fd)
    if err != nil {
        if err == unix.EAGAIN || err == unix.ECONNABORTED {
            return nil
        }
        svr.opts.Logger.Errorf("Accept() fails due to error: %v", err)
        return errors.ErrAcceptSocket
    }
    if err = os.NewSyscallError("fcntl nonblock", unix.SetNonblock(nfd, true)); err != nil {
        return err
    }

    remoteAddr := socket.SockaddrToTCPOrUnixAddr(sa)
    if svr.opts.TCPKeepAlive > 0 && svr.ln.network == "tcp" {
        err = socket.SetKeepAlive(nfd, int(svr.opts.TCPKeepAlive/time.Second))
        logging.Error(err)
    }

    // Set RecvBufferSize
    if svr.opts.SocketRecvBuffer > 0 {
        err = socket.SetRecvBuffer(nfd, svr.opts.SocketRecvBuffer)
        logging.Error(err)
    }

    // SetSendBufferSize
    if svr.opts.SocketSendBuffer > 0 {
        err = socket.SetSendBuffer(nfd, svr.opts.SocketRecvBuffer)
        logging.Error(err)
    }

    // Disabling TIME_WAIT state
    l := unix.Linger{
        Onoff:  0,
        Linger: 0,
    }
    err = unix.SetsockoptLinger(nfd, unix.SOL_SOCKET, unix.SO_LINGER, &l)
    if err != nil {
        logging.Error(err)
    }

    el := svr.lb.next(remoteAddr)
    c := newTCPConn(nfd, el, sa, svr.opts.Codec, el.ln.addr, remoteAddr)

    err = el.poller.UrgentTrigger(el.register, c)
    if err != nil {
        _ = unix.Close(nfd)
        c.releaseTCP()
    }
    return nil
}


### How to Reproduce

Steps to reproduce the behavior:
1. Go to '....'
2. Click on '....'
3. Do '....'
4. See '....'

### Does this issue reproduce with the latest release?

It can reproduce with the latest release
panjf2000 commented 1 year ago

根据 TCP 协议标准,通过 accept 返回的新 sockets 会从 listening socket 继承以下 socket options:

在 Linux 系统上,accpet 返回的 socket 不会继承 file flags 比如 O_NONBLOCK/O_ASYNC,而 BSD 系统则会连 file flags 也一起继承下来,所以并不需要再次显式设置。