总结
就很清晰能看到这样的一个流程
accept4 -> epoll_ctl(ADD) -> epoll_wait() -> read() -> epoll_ctl(DEL) -> close
用strace看net.Listener的Accept函数
目标观察go netpoll中,epoll的使用情况
package main
import (
"fmt"
"net"
)
func main() {
ln, _ := net.Listen("tcp", ":9999")
defer ln.Close()
fmt.Println("listen :9999")
c, err := ln.Accept()
if err != nil {
return
}
defer c.Close()
buf := make([]byte, 32)
n, _ := c.Read(buf)
fmt.Printf("recv: %s", buf[:n])
}
操作
使用 nc 127.0.0.1 9999 进行通信,得到以下strace日志
strace
strace -f -e trace=%network,%desc -o goepoll.strace ././go_netepoll
10790 <... mmap resumed>) = 0x75cc70000000
10785 <... fcntl resumed>) = 0x8002 (flags O_RDWR|O_LARGEFILE)
10785 fcntl(1, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
10785 fcntl(2, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)
10785 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_TCP) = 3
10785 close(3 <unfinished ...>
10789 mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 <unfinished ...>
10785 <... close resumed>) = 0
10785 socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_TCP <unfinished ...>
10789 <... mmap resumed>) = 0x75cc8c848000
10785 <... socket resumed>) = 3
10785 setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
10785 bind(3, {sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_scope_id=0}, 28) = 0
10785 socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_TCP) = 4
10785 setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
10785 bind(4, {sa_family=AF_INET6, sin6_port=htons(0), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, 28) = 0
10785 close(4) = 0
10785 close(3) = 0
10785 socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
10785 setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
10785 openat(AT_FDCWD, "/proc/sys/net/core/somaxconn", O_RDONLY|O_CLOEXEC) = 4
10785 fcntl(4, F_GETFL) = 0x8000 (flags O_RDONLY|O_LARGEFILE)
10785 fcntl(4, F_SETFL, O_RDONLY|O_NONBLOCK|O_LARGEFILE) = 0
10785 epoll_create1(EPOLL_CLOEXEC) = 5
10785 eventfd2(0, EFD_CLOEXEC|EFD_NONBLOCK) = 6
10785 epoll_ctl(5, EPOLL_CTL_ADD, 6, {events=EPOLLIN, data={u32=7379064, u64=7379064}}) = 0
10785 epoll_ctl(5, EPOLL_CTL_ADD, 4, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=1051721729, u64=8488314593086537729}}) = 0
10786 epoll_pwait(5, [{events=EPOLLIN|EPOLLOUT, data={u32=1051721729, u64=8488314593086537729}}], 128, 0, NULL, 0) = 1
10785 read(4, "4096\n", 65536) = 5
10785 read(4, "", 65531) = 0
10785 epoll_ctl(5, EPOLL_CTL_DEL, 4, 0xc00009d924) = 0
10785 close(4) = 0
10785 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
10785 bind(3, {sa_family=AF_INET6, sin6_port=htons(9999), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, 28) = 0
10785 listen(3, 4096) = 0
10785 epoll_ctl(5, EPOLL_CTL_ADD, 3, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=1051721730, u64=8488314593086537730}}) = 0
10785 getsockname(3, {sa_family=AF_INET6, sin6_port=htons(9999), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::", &sin6_addr), sin6_scope_id=0}, [112 => 28]) = 0
10785 write(1, "listen :9999\n", 13) = 13
10785 accept4(3, 0xc00009dbcc, [112], SOCK_CLOEXEC|SOCK_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
10785 epoll_pwait(5, [], 128, 0, NULL, 0) = 0
10785 epoll_pwait(5, [{events=EPOLLIN, data={u32=1051721730, u64=8488314593086537730}}], 128, -1, NULL, 0) = 1
10785 accept4(3, {sa_family=AF_INET6, sin6_port=htons(33598), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, [112 => 28], SOCK_CLOEXEC|SOCK_NONBLOCK) = 4
10785 epoll_ctl(5, EPOLL_CTL_ADD, 4, {events=EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, data={u32=1033371649, u64=8488314593068187649}}) = 0
10785 getsockname(4, {sa_family=AF_INET6, sin6_port=htons(9999), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_scope_id=0}, [112 => 28]) = 0
10785 setsockopt(4, SOL_TCP, TCP_NODELAY, [1], 4) = 0
10785 setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
10785 setsockopt(4, SOL_TCP, TCP_KEEPIDLE, [15], 4) = 0
10785 setsockopt(4, SOL_TCP, TCP_KEEPINTVL, [15], 4) = 0
10785 setsockopt(4, SOL_TCP, TCP_KEEPCNT, [9], 4) = 0
10785 read(4, 0xc00001e0c0, 32) = -1 EAGAIN (Resource temporarily unavailable)
10785 epoll_pwait(5, [{events=EPOLLOUT, data={u32=1033371649, u64=8488314593068187649}}], 128, 0, NULL, 0) = 1
10785 epoll_pwait(5, [{events=EPOLLIN|EPOLLOUT, data={u32=1033371649, u64=8488314593068187649}}], 128, -1, NULL, 0) = 1
10785 read(4, "asdf\n", 32) = 5
10785 write(1, "recv: asdf\n", 11) = 11
10785 epoll_ctl(5, EPOLL_CTL_DEL, 4, 0xc00009dd2c) = 0
10785 close(4) = 0
10785 epoll_ctl(5, EPOLL_CTL_DEL, 3, 0xc00009dd44) = 0
10785 close(3) = 0
参考:
https://github.com/golang/go/blob/master/src/runtime/netpoll.go