golang 设置socket配置信息
开发高性能server的时候,不可避免的需要对原生socket做一些配置调优,包括设置io复用、接收发送缓存大小等
如果使用io复用,必须要设置监听socket为SO_REUSEADDR和SO_REUSEPORT。设置复用端口和地址还有个好处,就是程序崩溃后,端口监听有可能没有释放,必须要等两分钟才能再次启动程序。如果是端口复用,就是不在乎启动几个进程,所以程序崩溃后可以立马启动新的。
lc := net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
//上面都是默认写法,这里是设置地址复用
err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if err != nil {
fmt.Println(err)
}
//这里是设置端口复用
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
if err != nil {
fmt.Println(err)
}
//这里是设置接收缓冲区大小为10M
err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF, 10*1024*1024)
if err != nil {
fmt.Println(err)
}
})
},
}
//udp的例子
lp, err := lc.ListenPacket(context.Background(), "udp", "0.0.0.0:1234")
if err != nil {
fmt.Println(err)
return
}
udpconn := lp.(*net.UDPConn)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
var data [1024]byte
for true {
_, _, err := udpconn.ReadFromUDP(data[:])
if err != nil {
fmt.Println(err)
return
}
}
}()
//TCP的例子
l, err := lc.Listen(context.Background(), "tcp", "0.0.0.0:9000")
if err != nil {
log.Printf("Could not start TCP listener: %s", err)
return
}
for {
c, err := l.Accept()
if err != nil {
log.Printf("Listener returned: %s", err)
break
}
go func() {
defer c.Close()
log.Printf("New connection created")
_, err := c.Write([]byte("Hello World"))
if err != nil {
log.Printf("Unable to write on connection: %s", err)
}
}()
}
除此之外,golang还针对UDPConn等提供了一些常见的设置api,比如SetWriteBuffer
可以通过官方文档查询。
有很多配置选项,也可以通过官方文档确认。
https://madflojo.medium.com/socket-options-go-multiple-listeners-one-port-7e5257044bb1
https://github.com/libp2p/go-reuseport
https://pkg.go.dev/syscall
https://pkg.go.dev/net