go1.18 tcp连接设置 keepalive选项不生效
1. 运行环境
操作系统win11或者ubuntu20.04
go1.18
2. 问题描述?
如下代码,tcp连接设置keepalive以后,tcp服务端仍然每15秒会收到tcp客户端发送的心跳包
package main
import (
"fmt"
"github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "net" "strings" "time")
// 才认识tcp是否可以设置
func main(){
// 连接服务器
go runDump()
time.Sleep(5*time.Second)
go func() {
tcpAddr, _ := net.ResolveTCPAddr("tcp4", "localhost:8080")
conn, err := net.DialTCP("tcp", nil, tcpAddr)
//conn,err := net.Dial("tcp","127.0.0.1:8080")
if err != nil {
fmt.Println("Connect to TCP server failed ,err:",err)
return
}
err=conn.SetKeepAlivePeriod(1000*time.Second)
fmt.Println("设置错误:",err)
fmt.Println("建立连接:",conn)
}()
address := &net.TCPAddr{
IP: net.ParseIP("127.0.0.1"), // 把字符串IP地址转换为net.IP类型
Port: 8080,
}
listener,err := net.ListenTCP("tcp",address)
if err != nil {
fmt.Println("Listen tcp server failed,err:",err)
return
}
for{
// 建立socket连接
conn,err := listener.Accept()
if err != nil {
fmt.Println("Listen.Accept failed,err:",err)
continue
}
fmt.Println("收到连接:",conn)
// 业务处理逻辑
//go process(conn)
}
}
var (
tcprecv = 0
tcpsend = 0
udprecv = 0
udpsend = 0
tcpurl = "localhost:8080"
udpurl = "localhost:8081"
)
func runDump() {
//var udpsum int64 = 0
//var tcpsum int64 = 0 var devices []pcap.Interface
devices, _ = pcap.FindAllDevs()
// 用同步的写法吧
length := len(devices)
for i := 0; i < length; i++ {
// 打印设备名字
fmt.Println(devices[i].Name)
handle, _ := pcap.OpenLive(devices[i].Name, int32(65535), true, -1*time.Second)
// 设置过滤表达式
handle.SetBPFFilter("port 8081 or port 8080")
// handle.SetBPFFilter("tcp and port 8080")
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packets := packetSource.Packets()
// 这里是阻塞,需要开协程
go func() {
for p := range packets {
//fmt.Println("p",p.)
// 打印第三层的长度
// 判断是tcp还是udp,接收端口还是发送端口
// 打印包长度
for _, layer := range p.Layers() {
fmt.Printf("协议层:%s,本层长度:%v,负载长度:%v\n",layer.LayerType(),len(layer.LayerContents()),len(layer.LayerPayload()))
}
if tcp := p.Layer(layers.LayerTypeTCP); tcp != nil {
// 统计websocket连接建立的字节数,这里应该用上一层协议的负载长度来计算
tcpLayer, _ := tcp.(*layers.TCP)
// fmt.Println("tcpLayer",len(tcpLayer.Contents))
if strings.Contains(tcpLayer.DstPort.String(),"8080") {
tcprecv+=len(tcpLayer.LayerContents())+len(tcpLayer.LayerPayload())
fmt.Println("8080端口接收到的ws包累计大小:",tcprecv)
}else{
tcpsend+=len(tcpLayer.LayerContents())+len(tcpLayer.LayerPayload())
// fmt.Println("8080端口发送的ws包累计大小:",tcpsend)
}
}
if udp := p.Layer(layers.LayerTypeUDP); udp != nil {
// 打印udp
udpLayer, _ := udp.(*layers.UDP)
// fmt.Println("udplen",len(udpLayer.LayerContents()))
if strings.Contains(udpLayer.DstPort.String(),"8081") {
//fmt.Println("udp:",len(udpLayer.Contents))
udprecv+=int(udpLayer.Length)
//fmt.Println("8081端口接收到的quic包累计大小:",udprecv)
}else{
udpsend+=int(udpLayer.Length)
//fmt.Println("8081端口发送的的quic包累计大小:",udpsend)
}
}
}
}()
}
}
3. 您期望得到的结果?
设置了keepalive时间间隔了,tcp应该建立连接以后就不会15s(系统默认时间间隔)发送心跳包了啊。,所以抓包的结果应该是第一次建立连接消耗的字节数啊
破案了。默认的tcp连接,客户端和服务端都会向对方发送心跳包,采用go默认的时间间隔15s.因此需要客户端服务端都设置keepalive :sob: