socket心跳超时机制

服务器端代码:
/**
* MyHeartbeatServer
* @Author:  Jian Junbo
* @Email:   [email protected]
* @Create:  2017/9/16 14:02
* Copyright (c) 2017 Jian Junbo All rights reserved.
*
* Description:
*/
package main

import (
	"fmt"
	"net"
	"os"
	"time"
)

func Log(v ...interface{}) {
	fmt.Println(v...)
	return
}
func main() {
	server := ":7373"
	netListen, err := net.Listen("tcp", server)
	if err != nil {
		Log("connect error: ", err)
		os.Exit(1)
	}
	Log("Waiting for Client ...")
	for {
		conn, err := netListen.Accept()
		if err != nil {
			Log(conn.RemoteAddr().String(), "Fatal error: ", err)
			continue
		}

		//设置短连接(10秒)每接收到一个连接就开始进行超时控制
		conn.SetReadDeadline(time.Now().Add(time.Duration(10) * time.Second))

		Log(conn.RemoteAddr().String(), "connect success!")
		go handleConnection(conn)
	}
}
func handleConnection(conn net.Conn) {
	buffer := make([]byte, 1024)
	for {
		n, err := conn.Read(buffer)
		if err != nil {
			Log(conn.RemoteAddr().String(), " Fatal error: ", err)
			return
		}
		Data := buffer[:n]
		//fmt.Println("slice",Data)
		//fmt.Println("string",string(Data))
		message := make(chan byte)
		//心跳计时
		go HeartBeating(conn, message, 4)//此处将超时时间重置为4S
		//检测每次是否有数据传入
		go GravelChannel(Data, message)
		Log(time.Now().Format("2006-01-02 15:04:05.0000000"), conn.RemoteAddr().String(), string(buffer[:n]))
	}
	defer conn.Close()
}

func GravelChannel(bytes []byte, mess chan byte) {

	for _, v := range bytes {
		fmt.Println("_____",v)
		mess <- v
	}
	close(mess)
}

func HeartBeating(conn net.Conn, bytes chan byte, timeout int) {
	select {
	case fk := <-bytes:
		Log(conn.RemoteAddr().String(), "心跳:第", string(fk), "times")
		conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
		break

	case <-time.After(5 * time.Second): //5S没有读到数据则
		Log("conn dead now")
		conn.Close()
	}
}
---------------------------------------------------------
---------------------------------------------------------
GOROOT=C:\Go #gosetup
GOPATH=D:\go;D:\Modbustest #gosetup
C:\Go\bin\go.exe build -o C:\Users\10209756\AppData\Local\Temp\___go_build_TcpServer_go.exe D:/Modbustest/src/TcpServer/TcpServer.go #gosetup
"C:\Program Files\JetBrains\GoLand 2018.3.1\bin\runnerw64.exe" C:\Users\10209756\AppData\Local\Temp\___go_build_TcpServer_go.exe #gosetup
Waiting for Client ...
127.0.0.1:62851 connect success!
_____ 48
_____ 72
127.0.0.1:62851 心跳:第 0 times
2018-12-29 10:42:16.0191878 127.0.0.1:62851 0Hello I'm MyHeartbeat Client.
2018-12-29 10:42:18.0184779 127.0.0.1:62851 1Hello I'm MyHeartbeat Client.
_____ 49
127.0.0.1:62851 心跳:第 1 times
_____ 72
2018-12-29 10:42:20.0246446 127.0.0.1:62851 2Hello I'm MyHeartbeat Client.
_____ 50
127.0.0.1:62851 心跳:第 2 times
_____ 72
2018-12-29 10:42:22.0251271 127.0.0.1:62851 3Hello I'm MyHeartbeat Client.
_____ 51
127.0.0.1:62851 心跳:第 3 times
_____ 72
2018-12-29 10:42:24.0256984 127.0.0.1:62851 4Hello I'm MyHeartbeat Client.
_____ 52
127.0.0.1:62851 心跳:第 4 times
_____ 72
2018-12-29 10:42:26.0259537 127.0.0.1:62851 5Hello I'm MyHeartbeat Client.
_____ 53
127.0.0.1:62851 心跳:第 5 times
_____ 72
2018-12-29 10:42:28.0262855 127.0.0.1:62851 6Hello I'm MyHeartbeat Client.
_____ 54
127.0.0.1:62851 心跳:第 6 times
_____ 72
2018-12-29 10:42:30.0264555 127.0.0.1:62851 7Hello I'm MyHeartbeat Client.
_____ 55
127.0.0.1:62851 心跳:第 7 times
_____ 72
2018-12-29 10:42:32.0265884 127.0.0.1:62851 8Hello I'm MyHeartbeat Client.
_____ 56
127.0.0.1:62851 心跳:第 8 times
_____ 72
2018-12-29 10:42:34.0317329 127.0.0.1:62851 9Hello I'm MyHeartbeat Client.
_____ 57
127.0.0.1:62851 心跳:第 9 times
_____ 72
127.0.0.1:62851  Fatal error:  read tcp 127.0.0.1:7373->127.0.0.1:62851: i/o timeout
很显然这样接收的数据channel底层开了10个channel堵塞住,因为是go协程触发看不出来效果
72--对应ASCLL---H
代码变更为:
func GravelChannel(bytes []byte, mess chan byte) {

	//for _, v := range bytes {
	//	fmt.Println("_____",v)
		mess <- bytes[0]
	//}
	close(mess)
}
客户端代码:
package main

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"time"
)

func Log(v ...interface{}) {
	fmt.Println(v...)
	return
}

func main() {
	server := "127.0.0.1:7373"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
	if err != nil {
		Log(os.Stderr, "Fatal error:", err.Error())
		os.Exit(1)//直接结束
	}
	conn, err := net.DialTCP("tcp", nil, tcpAddr)//返回值是*TCPConn不是
	if err != nil {
		Log("Fatal error:", err.Error())
		os.Exit(1)
	}
	Log(conn.RemoteAddr().String(), "connection succcess!")
	sender(conn)
	Log("send over")
}

func sender(conn *net.TCPConn) {
	for i := 0; i < 10; i++ {
		words := strconv.Itoa(i) + "Hello I'm MyHeartbeat Client."
		msg, err := conn.Write([]byte(words))
		if err != nil {
			Log(conn.RemoteAddr().String(), "Fatal error: ", err)
			os.Exit(1)
		}
		Log("服务端接收了",string([]byte(words)[:msg]))
		time.Sleep(2 * time.Second)
	}
	for i := 0; i < 2; i++ {
		time.Sleep(12 * time.Second)
	}
	for i := 0; i < 10; i++ {
		words := strconv.Itoa(i) + "Hi I'm MyHeartbeat Client."
		msg, err := conn.Write([]byte(words))
		if err != nil {
			Log(conn.RemoteAddr().String(), "Fatal error: ", err)
			os.Exit(1)
		}
		Log("服务端接收了", msg)
		time.Sleep(2 * time.Second)
	}
}

 理解下面的细节:

 服务器端接收数据的for循环最后一步要增加一行:对缓存数据buffer清空,防止下一次循环读取数据的时候出问题

buffer = make([]byte, 1024)//清空缓存数据
发布了67 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42544051/article/details/85335518