内容简介:在多客户端同时访问因此,针对短链接和长连接,根据业务的需求,配套不同的处理机制。一般建立完连接,就立刻传输数据。传输完数据,连接就关闭。服务端根据需要,设定连接的时长。超过时间长度,就算客户端超时。立刻关闭连接。
在多客户端同时访问 服务器 的工作模式下,首先要保证服务器的运行正常。因此,Server和Client建立通讯后,确保连接的及时断开就非常重要。否则,多个客户端长时间占用着连接不关闭,是非常可怕的服务器资源浪费。会使得服务器可服务的客户端数量大幅度减少。
因此,针对短链接和长连接,根据业务的需求,配套不同的处理机制。
短连接
一般建立完连接,就立刻传输数据。传输完数据,连接就关闭。服务端根据需要,设定连接的时长。超过时间长度,就算客户端超时。立刻关闭连接。
长连接
建立连接后,传输数据,然后要保持连接,然后再次传输数据。直到连接关闭。
socket读写可以通过 SetDeadline、SetReadDeadline、SetWriteDeadline设置阻塞的时间。
-
func (*IPConn) SetDeadline
-
func (c *IPConn) SetDeadline (t time.Time) error
-
func (*IPConn) SetReadDeadline
-
func (c *IPConn) SetReadDeadline (t time.Time) error
-
func (*IPConn) SetWriteDeadline
-
func (c *IPConn) SetWriteDeadline (t time.Time) error
如果做短连接,直接在Server端的连接上设置SetReadDeadline。当你设置的时限到达,无论客户端是否还在继续传递消息,服务端都不会再接收。并且已经关闭连接。
-
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!" )
-
...
-
}
-
}
这就可以了。在这段代码中,每当10秒中的时限一道,连接就终止了。
根据业务需要,客户端可能需要长时间保持连接。但是服务端不能无限制的保持。这就需要一个机制,如果超过某个时间长度,服务端没有获得客户端的数据,就判定客户端已经不需要连接了(比如客户端挂掉了)。
做到这个,需要一个心跳机制。在限定的时间内,客户端给服务端发送一个指定的消息,以便服务端知道客户端还活着。
-
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( "服务端接收了" , 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)
-
}
-
}
这段客户端代码,实现了两个相同的信息发送频率给服务端。两个频率中间,我们让运行休息了12秒。然后,我们在服务端的对应机制是这样的。
-
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):
-
Log( "conn dead now" )
-
conn.Close()
-
}
-
}
每次接收到心跳数据就 SetDeadline 延长一个时间段 timeout。如果没有接到心跳数据,5秒后连接关闭。
服务端完整代码示例
-
/**
-
* MyHeartbeatServer
-
* @Author: Jian Junbo
-
* @Email: junbojian@qq.com
-
* @Create: 2017/9/16 14:02
-
* Copyright (c) 2017 Jian Junbo All rights reserved.
-
*
-
* Description:
-
*/
-
package main
-
import (
-
"net"
-
"fmt"
-
"os"
-
"time"
-
)
-
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]
-
message := make ( chan byte )
-
//心跳计时
-
go HeartBeating(conn, message, 4 )
-
//检测每次是否有数据传入
-
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{
-
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):
-
Log( "conn dead now" )
-
conn.Close()
-
}
-
}
-
func Log (v ... interface {}) {
-
fmt.Println(v...)
-
return
-
}
客户端完整代码示例
-
/**
-
* MyHeartbeatClient
-
* @Author: Jian Junbo
-
* @Email: junbojian@qq.com
-
* @Create: 2017/9/16 14:21
-
* Copyright (c) 2017 Jian Junbo All rights reserved.
-
*
-
* Description:
-
*/
-
package main
-
import (
-
"net"
-
"fmt"
-
"os"
-
"strconv"
-
"time"
-
)
-
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)
-
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( "服务端接收了" , 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)
-
}
-
}
-
func Log (v ... interface {}) {
-
fmt.Println(v...)
-
return
-
}
参考:
https://www.yuque.com/docs/share/ef732d9e-f488-4e7e-8d64-43a1c18872ea
以上所述就是小编给大家介绍的《Golang 心跳的实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
URL 编码/解码
URL 编码/解码