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(系统默认时间间隔)发送心跳包了啊。,所以抓包的结果应该是第一次建立连接消耗的字节数啊

4. 您实际得到的结果?

最佳答案

破案了。默认的tcp连接,客户端和服务端都会向对方发送心跳包,采用go默认的时间间隔15s.因此需要客户端服务端都设置keepalive :sob:

2年前 评论
讨论数量: 1

破案了。默认的tcp连接,客户端和服务端都会向对方发送心跳包,采用go默认的时间间隔15s.因此需要客户端服务端都设置keepalive :sob:

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!