From 8224c3e8bfb163d8e2b0fa5c731856ce5973d524 Mon Sep 17 00:00:00 2001 From: Joway Date: Thu, 9 Sep 2021 18:50:33 +0800 Subject: [PATCH] feat: support TCP_NODELAY (#39) * feat: support TCP_NODELAY * feat: default tcp_nodelay = true * feat: hide intertal interface * chore: fix tests --- connection_impl.go | 5 +++++ connection_test.go | 14 ++++++++++++++ go.sum | 2 -- sys_exec.go | 13 +++++++++++++ sys_sockopt_linux.go | 8 -------- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/connection_impl.go b/connection_impl.go index 09d55608..a7494337 100644 --- a/connection_impl.go +++ b/connection_impl.go @@ -264,6 +264,11 @@ func (c *connection) init(conn Conn, prepare OnPrepare) (err error) { c.inputBarrier, c.outputBarrier = barrierPool.Get().(*barrier), barrierPool.Get().(*barrier) c.setFinalizer() + // enable TCP_NODELAY by default + switch c.network { + case "tcp", "tcp4", "tcp6": + setTCPNoDelay(c.fd, true) + } // check zero-copy if setZeroCopy(c.fd) == nil && setBlockZeroCopySend(c.fd, defaultZeroCopyTimeoutSec, 0) == nil { c.supportZeroCopy = true diff --git a/connection_test.go b/connection_test.go index 1a078ca2..ea785ada 100644 --- a/connection_test.go +++ b/connection_test.go @@ -233,3 +233,17 @@ func TestConnectionLargeMemory(t *testing.T) { panic(fmt.Sprintf("alloc[%d] out of memory %d", alloc, limit)) } } + +// TestSetTCPNoDelay is used to verify the connection initialization set the TCP_NODELAY correctly +func TestSetTCPNoDelay(t *testing.T) { + fd, err := sysSocket(syscall.AF_INET, syscall.SOCK_STREAM, 0) + conn := &connection{} + conn.init(&netFD{network: "tcp", fd: fd}, nil) + + n, _ := syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY) + MustTrue(t, n > 0) + err = setTCPNoDelay(fd, false) + MustNil(t, err) + n, _ = syscall.GetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY) + MustTrue(t, n == 0) +} diff --git a/go.sum b/go.sum index c022ebc3..7618b6e9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/bytedance/gopkg v0.0.0-20210507130052-24980f04837a h1:wjM2Z8ZV1OjQMyVSoXIDqjWK5BEuRHT+S6kLH1BVR5c= -github.com/bytedance/gopkg v0.0.0-20210507130052-24980f04837a/go.mod h1:birsdqRCbwnckJbdAvcSao+AzOyibVEoWB55MjpYpB8= github.com/bytedance/gopkg v0.0.0-20210705062217-74c74ebadcae h1:ERLYTdHnm2E8jwpprhHPvBhbPBaxnwl62tb3lR8Nd+k= github.com/bytedance/gopkg v0.0.0-20210705062217-74c74ebadcae/go.mod h1:birsdqRCbwnckJbdAvcSao+AzOyibVEoWB55MjpYpB8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= diff --git a/sys_exec.go b/sys_exec.go index 224f3367..33122adf 100644 --- a/sys_exec.go +++ b/sys_exec.go @@ -28,6 +28,11 @@ func GetSysFdPairs() (r, w int) { return fds[0], fds[1] } +// setTCPNoDelay set the TCP_NODELAY flag on socket +func setTCPNoDelay(fd int, b bool) (err error) { + return syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(b)) +} + // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. func sysSocket(family, sotype, proto int) (int, error) { @@ -101,3 +106,11 @@ func iovecs(bs [][]byte, ivs []syscall.Iovec) (iovLen int) { } return iovLen } + +// Boolean to int. +func boolint(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/sys_sockopt_linux.go b/sys_sockopt_linux.go index def023bd..5a7dddce 100644 --- a/sys_sockopt_linux.go +++ b/sys_sockopt_linux.go @@ -23,11 +23,3 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { // Allow broadcast. return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)) } - -// Boolean to int. -func boolint(b bool) int { - if b { - return 1 - } - return 0 -}