From 9f8e88b863dc23866a9a14c22bf3a5b43c7d2e0b Mon Sep 17 00:00:00 2001
From: esrrhs <esrrhs@163.com>
Date: Sat, 22 Dec 2018 17:25:59 +0800
Subject: [PATCH] add

---
 client.go     | 67 ++++++++++++++++++++++++++++++++++-----------------
 cmd/main.go   |  2 +-
 pingtunnel.go |  1 -
 3 files changed, 46 insertions(+), 24 deletions(-)

diff --git a/client.go b/client.go
index 1deab02..e6c04d3 100644
--- a/client.go
+++ b/client.go
@@ -64,15 +64,18 @@ type Client struct {
 	recvPacket     uint64
 	sendPacketSize uint64
 	recvPacketSize uint64
-
-	sendHBPacket uint64
 }
 
 type ClientConn struct {
-	ipaddr     *net.UDPAddr
-	id         string
-	activeTime time.Time
-	close      bool
+	ipaddr        *net.UDPAddr
+	id            string
+	activeTime    time.Time
+	close         bool
+	recvPacket    uint64
+	avgRecvNum    uint64
+	avgRecvPacket uint64
+	hbPacket      uint64
+	sendHBPacket  uint64
 }
 
 func (p *Client) Addr() string {
@@ -124,14 +127,7 @@ func (p *Client) Run() {
 	interval := time.NewTicker(time.Second)
 	defer interval.Stop()
 
-	inter := 1000
-	if p.hb > 0 {
-		inter := 1000 / p.hb
-		if inter <= 0 {
-			inter = 1
-		}
-	}
-	intervalHB := time.NewTicker(time.Millisecond * (time.Duration)(inter))
+	intervalHB := time.NewTicker(time.Millisecond * 10)
 	defer intervalHB.Stop()
 
 	for {
@@ -140,6 +136,7 @@ func (p *Client) Run() {
 			p.checkTimeoutConn()
 			p.ping()
 			p.showNet()
+			p.calcHB()
 		case <-intervalHB.C:
 			p.heartbeat()
 		case r := <-recv:
@@ -215,6 +212,7 @@ func (p *Client) processPacket(packet *Packet) {
 
 	now := time.Now()
 	clientConn.activeTime = now
+	clientConn.recvPacket++
 
 	_, err := p.listenConn.WriteToUDP(packet.data, addr)
 	if err != nil {
@@ -262,13 +260,12 @@ func (p *Client) ping() {
 }
 
 func (p *Client) showNet() {
-	fmt.Printf("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s HB %d/s\n",
-		p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024, p.sendHBPacket)
+	fmt.Printf("send %dPacket/s %dKB/s recv %dPacket/s %dKB/s\n",
+		p.sendPacket, p.sendPacketSize/1024, p.recvPacket, p.recvPacketSize/1024)
 	p.sendPacket = 0
 	p.recvPacket = 0
 	p.sendPacketSize = 0
 	p.recvPacketSize = 0
-	p.sendHBPacket = 0
 }
 
 func (p *Client) heartbeat() {
@@ -276,13 +273,39 @@ func (p *Client) heartbeat() {
 	if p.hb > 0 {
 		for _, conn := range p.localIdToConnMap {
 
-			b := make([]byte, 4)
-			binary.BigEndian.PutUint32(b[:4], rand.Uint32())
-			sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, conn.id, (uint32)(HB), b, p.sproto, p.rproto)
-			p.sequence++
+			if conn.sendHBPacket < conn.hbPacket {
 
-			p.sendHBPacket++
+				b := make([]byte, 4)
+				binary.BigEndian.PutUint32(b[:4], rand.Uint32())
+				sendICMP(p.id, p.sequence, *p.conn, p.ipaddrServer, p.targetAddr, conn.id, (uint32)(HB), b, p.sproto, p.rproto)
+				p.sequence++
 
+				conn.sendHBPacket++
+
+			}
+		}
+	}
+}
+
+func (p *Client) calcHB() {
+
+	if p.hb > 0 {
+		for _, conn := range p.localIdToConnMap {
+
+			conn.avgRecvPacket = (conn.recvPacket + conn.avgRecvPacket*conn.avgRecvNum) / conn.avgRecvNum
+			conn.avgRecvNum++
+			if conn.avgRecvNum > 10 {
+				conn.avgRecvNum = 0
+			}
+			conn.recvPacket = 0
+
+			conn.hbPacket = conn.avgRecvPacket * 2 / 3
+
+			if conn.hbPacket > 0 {
+				fmt.Printf("calcHB %s %s %d %d\n", conn.id, conn.ipaddr.String(), conn.hbPacket, conn.sendHBPacket)
+			}
+
+			conn.sendHBPacket = 0
 		}
 	}
 }
diff --git a/cmd/main.go b/cmd/main.go
index 25ca475..e9f6124 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -37,7 +37,7 @@ Usage:
     -rproto   客户端接收ping协议的协议,默认是0
               The protocol that the client receives the ping. The default is 0.
 
-    -hb       客户端保持每秒发到服务器的心跳包,用于在某些网络下更新服务器的id和seq,以接收到服务器的reply
+    -hb       客户端自动保持每秒发到服务器的心跳包,用于在某些网络下更新服务器的id和seq,以接收到服务器的reply,默认0关闭
 `
 
 func main() {
diff --git a/pingtunnel.go b/pingtunnel.go
index 646d46b..9a0ba30 100644
--- a/pingtunnel.go
+++ b/pingtunnel.go
@@ -22,7 +22,6 @@ const (
 	END  uint32 = 0xAAAABBBB
 )
 
-// An Echo represents an ICMP echo request or reply message body.
 type MyMsg struct {
 	TYPE    uint32
 	ID      string