服务器端代码:
/**
* 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)//清空缓存数据