Golang 心跳的实现

栏目: Go · 发布时间: 5年前

内容简介:在多客户端同时访问因此,针对短链接和长连接,根据业务的需求,配套不同的处理机制。一般建立完连接,就立刻传输数据。传输完数据,连接就关闭。服务端根据需要,设定连接的时长。超过时间长度,就算客户端超时。立刻关闭连接。

在多客户端同时访问 服务器 的工作模式下,首先要保证服务器的运行正常。因此,Server和Client建立通讯后,确保连接的及时断开就非常重要。否则,多个客户端长时间占用着连接不关闭,是非常可怕的服务器资源浪费。会使得服务器可服务的客户端数量大幅度减少。

因此,针对短链接和长连接,根据业务的需求,配套不同的处理机制。

短连接

一般建立完连接,就立刻传输数据。传输完数据,连接就关闭。服务端根据需要,设定连接的时长。超过时间长度,就算客户端超时。立刻关闭连接。

长连接

建立连接后,传输数据,然后要保持连接,然后再次传输数据。直到连接关闭。

socket读写可以通过 SetDeadline、SetReadDeadline、SetWriteDeadline设置阻塞的时间。

  1. func (*IPConn) SetDeadline

  2. func (c *IPConn) SetDeadline (t time.Time) error

  3. func (*IPConn) SetReadDeadline

  4. func (c *IPConn) SetReadDeadline (t time.Time) error

  5. func (*IPConn) SetWriteDeadline

  6. func (c *IPConn) SetWriteDeadline (t time.Time) error

如果做短连接,直接在Server端的连接上设置SetReadDeadline。当你设置的时限到达,无论客户端是否还在继续传递消息,服务端都不会再接收。并且已经关闭连接。

  1. func main () {

  2. server := ":7373"

  3. netListen, err := net.Listen( "tcp" , server)

  4. if err != nil {

  5. Log( "connect error: " , err)

  6. os.Exit( 1 )

  7. }

  8. Log( "Waiting for Client ..." )

  9. for {

  10. conn, err := netListen.Accept()

  11. if err != nil {

  12. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  13. continue

  14. }

  15. //设置短连接(10秒)

  16. conn.SetReadDeadline(time.Now().Add(time.Duration( 10 )*time.Second))

  17. Log(conn.RemoteAddr().String(), "connect success!" )

  18. ...

  19. }

  20. }

这就可以了。在这段代码中,每当10秒中的时限一道,连接就终止了。

根据业务需要,客户端可能需要长时间保持连接。但是服务端不能无限制的保持。这就需要一个机制,如果超过某个时间长度,服务端没有获得客户端的数据,就判定客户端已经不需要连接了(比如客户端挂掉了)。

做到这个,需要一个心跳机制。在限定的时间内,客户端给服务端发送一个指定的消息,以便服务端知道客户端还活着。

  1. func sender (conn *net.TCPConn) {

  2. for i := 0 ; i < 10 ; i++{

  3. words := strconv.Itoa(i)+ " Hello I'm MyHeartbeat Client."

  4. msg, err := conn.Write([] byte (words))

  5. if err != nil {

  6. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  7. os.Exit( 1 )

  8. }

  9. Log( "服务端接收了" , msg)

  10. time.Sleep( 2 * time.Second)

  11. }

  12. for i := 0 ; i < 2 ; i++ {

  13. time.Sleep( 12 * time.Second)

  14. }

  15. for i := 0 ; i < 10 ; i++{

  16. words := strconv.Itoa(i)+ " Hi I'm MyHeartbeat Client."

  17. msg, err := conn.Write([] byte (words))

  18. if err != nil {

  19. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  20. os.Exit( 1 )

  21. }

  22. Log( "服务端接收了" , msg)

  23. time.Sleep( 2 * time.Second)

  24. }

  25. }

这段客户端代码,实现了两个相同的信息发送频率给服务端。两个频率中间,我们让运行休息了12秒。然后,我们在服务端的对应机制是这样的。

  1. func HeartBeating (conn net.Conn, bytes chan byte , timeout int ) {

  2. select {

  3. case fk := <- bytes:

  4. Log(conn.RemoteAddr().String(), "心跳:第" , string (fk), "times" )

  5. conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))

  6. break

  7. case <- time.After( 5 * time.Second):

  8. Log( "conn dead now" )

  9. conn.Close()

  10. }

  11. }

每次接收到心跳数据就 SetDeadline 延长一个时间段 timeout。如果没有接到心跳数据,5秒后连接关闭。

服务端完整代码示例

  1. /**

  2. * MyHeartbeatServer

  3. * @Author: Jian Junbo

  4. * @Email: junbojian@qq.com

  5. * @Create: 2017/9/16 14:02

  6. * Copyright (c) 2017 Jian Junbo All rights reserved.

  7. *

  8. * Description:

  9. */

  10. package main

  11. import (

  12. "net"

  13. "fmt"

  14. "os"

  15. "time"

  16. )

  17. func main () {

  18. server := ":7373"

  19. netListen, err := net.Listen( "tcp" , server)

  20. if err != nil {

  21. Log( "connect error: " , err)

  22. os.Exit( 1 )

  23. }

  24. Log( "Waiting for Client ..." )

  25. for {

  26. conn, err := netListen.Accept()

  27. if err != nil {

  28. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  29. continue

  30. }

  31. //设置短连接(10秒)

  32. conn.SetReadDeadline(time.Now().Add(time.Duration( 10 )*time.Second))

  33. Log(conn.RemoteAddr().String(), "connect success!" )

  34. go handleConnection(conn)

  35. }

  36. }

  37. func handleConnection (conn net.Conn) {

  38. buffer := make ([] byte , 1024 )

  39. for {

  40. n, err := conn.Read(buffer)

  41. if err != nil {

  42. Log(conn.RemoteAddr().String(), " Fatal error: " , err)

  43. return

  44. }

  45. Data := buffer[:n]

  46. message := make ( chan byte )

  47. //心跳计时

  48. go HeartBeating(conn, message, 4 )

  49. //检测每次是否有数据传入

  50. go GravelChannel(Data, message)

  51. Log(time.Now().Format( "2006-01-02 15:04:05.0000000" ), conn.RemoteAddr().String(), string (buffer[:n]))

  52. }

  53. defer conn.Close()

  54. }

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

  56. for _, v := range bytes{

  57. mess <- v

  58. }

  59. close (mess)

  60. }

  61. func HeartBeating (conn net.Conn, bytes chan byte , timeout int ) {

  62. select {

  63. case fk := <- bytes:

  64. Log(conn.RemoteAddr().String(), "心跳:第" , string (fk), "times" )

  65. conn.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second))

  66. break

  67. case <- time.After( 5 * time.Second):

  68. Log( "conn dead now" )

  69. conn.Close()

  70. }

  71. }

  72. func Log (v ... interface {}) {

  73. fmt.Println(v...)

  74. return

  75. }

客户端完整代码示例

  1. /**

  2. * MyHeartbeatClient

  3. * @Author: Jian Junbo

  4. * @Email: junbojian@qq.com

  5. * @Create: 2017/9/16 14:21

  6. * Copyright (c) 2017 Jian Junbo All rights reserved.

  7. *

  8. * Description:

  9. */

  10. package main

  11. import (

  12. "net"

  13. "fmt"

  14. "os"

  15. "strconv"

  16. "time"

  17. )

  18. func main () {

  19. server := "127.0.0.1:7373"

  20. tcpAddr, err := net.ResolveTCPAddr( "tcp4" ,server)

  21. if err != nil {

  22. Log(os.Stderr, "Fatal error:" ,err.Error())

  23. os.Exit( 1 )

  24. }

  25. conn, err := net.DialTCP( "tcp" , nil ,tcpAddr)

  26. if err != nil {

  27. Log( "Fatal error:" ,err.Error())

  28. os.Exit( 1 )

  29. }

  30. Log(conn.RemoteAddr().String(), "connection succcess!" )

  31. sender(conn)

  32. Log( "send over" )

  33. }

  34. func sender (conn *net.TCPConn) {

  35. for i := 0 ; i < 10 ; i++{

  36. words := strconv.Itoa(i)+ " Hello I'm MyHeartbeat Client."

  37. msg, err := conn.Write([] byte (words))

  38. if err != nil {

  39. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  40. os.Exit( 1 )

  41. }

  42. Log( "服务端接收了" , msg)

  43. time.Sleep( 2 * time.Second)

  44. }

  45. for i := 0 ; i < 2 ; i++ {

  46. time.Sleep( 12 * time.Second)

  47. }

  48. for i := 0 ; i < 10 ; i++{

  49. words := strconv.Itoa(i)+ " Hi I'm MyHeartbeat Client."

  50. msg, err := conn.Write([] byte (words))

  51. if err != nil {

  52. Log(conn.RemoteAddr().String(), "Fatal error: " , err)

  53. os.Exit( 1 )

  54. }

  55. Log( "服务端接收了" , msg)

  56. time.Sleep( 2 * time.Second)

  57. }

  58. }

  59. func Log (v ... interface {}) {

  60. fmt.Println(v...)

  61. return

  62. }

参考:

https://www.yuque.com/docs/share/ef732d9e-f488-4e7e-8d64-43a1c18872ea


以上所述就是小编给大家介绍的《Golang 心跳的实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

终极算法

终极算法

[美] 佩德罗·多明戈斯 / 黄芳萍 / 中信出版集团 / 2017-1-1 / 68.00元

算法已在多大程度上影响我们的生活? 购物网站用算法来为你推荐商品,点评网站用算法来帮你选择餐馆,GPS系统用算法来帮你选择最佳路线,公司用算法来选择求职者…… 当机器最终学会如何学习时,将会发生什么? 不同于传统算法,现在悄然主导我们生活的是“能够学习的机器”,它们通过学习我们琐碎的数据,来执行任务;它们甚至在我们还没提出要求,就能完成我们想做的事。 什么是终极算法? ......一起来看看 《终极算法》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码