2020-08-22

1 篇文章 0 订阅
1 篇文章 0 订阅

go websokcet实战(1)

1.背景

       最近做HIDS项目中遇到一个需求,需要server端能随时主动给client端推送策略消息,而不需要等待client端的心跳消息上报。系统原有通信方式使用的http,server不具备这种能力,所有需要将系统的通信方式更改为websocket的方式。
       使用的过程中查找了一些资料,但是我们这边的有一个需求点是,希望server端每间隔一定时间(比如2小时)主动断开连接在这个server上的所有连接,让client端重新连接。原因是server端是分布式的,有10个实例,如果不周期性的进行断开重连,一旦一个server崩溃重启后,就没有client能连接这个server实例了。

2.什么是websokcet协议

       WebSocket是基于TCP的应用层协议,用于在C/S架构的应用中实现双向通信,关于WebSocket协议的详细规范和定义参见rfc6455。虽然WebSocket协议在建立连接时会使用HTTP协议,但这并不意味着WebSocket协议是基于HTTP协议实现的。详见https://www.cnblogs.com/nuccch/p/10947256.html
       websocket协议的使用场景:
1.有双向通信的需求
2.通信频繁,提升通信效率的需求

3.使用库

       go语言自带一个websocket相关的库 golang.org/x/net,但是查资料,发现说github上的github.com/gorilla/websocket库比自带的更好用,性能更好,就果断选择了github.com/gorilla/websocket 库进行研究。

3.1客户端发起连接创建

客户端通过Dialer函数发起连接的创建,然后通过创建的链接对象来发送消息。

url := "要连接的服务端地址"
dialer := &websocket.Dialer{
        Proxy:            http.ProxyFromEnvironment,
		HandshakeTimeout: 120 * time.Second,
	}
client, _, err := dialer.Dial(url, nil)

不断的从chan中取出消息,然后发送消息给server端。

reportMsgChan := make(chan []byte, 10)
for {
    select {
    case msg := <-reportMsgChan:
        err := client.Conn.WriteMessage(websocket.BinaryMessage, msg)
        if err != nil {
            reportMsgChan <- msg
            client.Conn.Close()
            goto DONE
        }
}
DONE:
	return
3.2服务端接收连接

服务端调用Upgrader.Upgrade 函数将来自客户端的http请求升级为长连接,获得一个连接对象*Conn:

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

func handler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println(err)
        return
    }
    for { // 使用conn接收来自客户端的消息
	    messageType, p, err := conn.ReadMessage()
	    if err != nil {
	        log.Println(err)
	        return
	    }
	    // 解析消息跑,并处理
	    ......
	}
}

4.其他注意事项

  1. 如果客户端有多个协程同时调用Write相关方法往server端发消息不允许的,会发生异常,解决的办法是在调用write相关的方法前先获取全局锁,以保证同一时刻只有一个协程调用次方法;另外一个解决办法就是上面展示的,使用chan,将需要发送的消息存入chan,然后由这个专门的发送数据的协程从chan中取出消息,来发送。
  2. 如果服务端主动关闭连接,为了不引起客户端的异常,可以提前给客户端发送一个CloseMessage类型,告诉客户端”我要关闭连接了“。
  3. conn的相关Write和Read系列方法,都是阻塞式的,为了提高系统的可用性,可设置接口的超时时间限制,避免因网络的原因造成接口阻塞,一直不能发送消息或者写消息,系统却无任何感知。(调用SetReadDeadline()或SetWriteDeadline()方法,当没有业务数据需要发送时,可以借助发送PingMessage或PongMessage)
    【参考】
    https://www.cnblogs.com/nuccch/p/10947256.html
    https://godoc.org/github.com/gorilla/websocket
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值