连接复用
- 原理:在高并发场景下,频繁创建和销毁TCP连接会消耗大量资源。连接复用即对已建立的连接进行重复使用,减少连接建立和关闭的开销。在Go语言中,
net/http
包中的Transport
结构体就支持连接复用。在TCP服务器场景下,我们可以通过维护一个连接池来实现连接复用。
- 代码示例:
package main
import (
"fmt"
"net"
"sync"
)
type ConnectionPool struct {
pool sync.Pool
}
func NewConnectionPool() *ConnectionPool {
return &ConnectionPool{
pool: sync.Pool{
New: func() interface{} {
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
return conn
},
},
}
}
func (cp *ConnectionPool) Get() net.Conn {
return cp.pool.Get().(net.Conn)
}
func (cp *ConnectionPool) Put(conn net.Conn) {
cp.pool.Put(conn)
}
缓冲区设置
- 原理:合理设置TCP连接的发送和接收缓冲区大小可以减少系统调用次数,提高数据传输效率。较大的缓冲区可以一次性传输更多数据,减少网络延迟,但也会占用更多内存。可以通过
SetReadBuffer
和SetWriteBuffer
方法来设置缓冲区大小。
- 代码示例:
package main
import (
"fmt"
"net"
)
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("Listen error:", err)
return
}
defer ln.Close()
conn, err := ln.Accept()
if err != nil {
fmt.Println("Accept error:", err)
return
}
defer conn.Close()
// 设置接收缓冲区大小为 32KB
err = conn.(*net.TCPConn).SetReadBuffer(32 * 1024)
if err != nil {
fmt.Println("SetReadBuffer error:", err)
}
// 设置发送缓冲区大小为 32KB
err = conn.(*net.TCPConn).SetWriteBuffer(32 * 1024)
if err != nil {
fmt.Println("SetWriteBuffer error:", err)
}
// 处理连接...
}
其他优化点
- 使用非阻塞I/O:通过
SetReadDeadline
和SetWriteDeadline
方法设置读写超时,避免I/O操作长时间阻塞。
package main
import (
"fmt"
"net"
"time"
)
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("Listen error:", err)
return
}
defer ln.Close()
conn, err := ln.Accept()
if err != nil {
fmt.Println("Accept error:", err)
return
}
defer conn.Close()
// 设置读超时为1秒
err = conn.SetReadDeadline(time.Now().Add(time.Second))
if err != nil {
fmt.Println("SetReadDeadline error:", err)
}
// 设置写超时为1秒
err = conn.SetWriteDeadline(time.Now().Add(time.Second))
if err != nil {
fmt.Println("SetWriteDeadline error:", err)
}
// 处理连接...
}
- 优化网络配置:例如启用TCP_NODELAY选项,禁用Nagle算法,让数据立即发送,减少延迟。
package main
import (
"fmt"
"net"
)
func main() {
ln, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
fmt.Println("Listen error:", err)
return
}
defer ln.Close()
conn, err := ln.Accept()
if err != nil {
fmt.Println("Accept error:", err)
return
}
defer conn.Close()
// 启用TCP_NODELAY
err = conn.(*net.TCPConn).SetNoDelay(true)
if err != nil {
fmt.Println("SetNoDelay error:", err)
}
// 处理连接...
}