pusher websocket client,基于golang
来源:互联网 发布:广州三箭汽枪淘宝网. 编辑:程序博客网 时间:2024/06/06 03:05
虚拟货币国内叫停,之前公司使用的是okcoin提供的交易数据,现在okcoin不更新了,需要更换数据源,bitstamp是一家国外的虚拟货币数据提供商,他们提供数据的方式是基于websocket的pusher推送。我作为client,自然要以pusher client的身份去订阅。
这个pusher和普通的websocket虽然本质一样,但是请求的方式不一样,正常的websocket请求是直接有一个ip和port,然后去dial建立连接。pusher的话是拿着一个key去连接pusher服务器,相当于是pusher是一个中间服务,为双方提供数据交互。
pusher官方提供的client没有go的实现,所以这块只能自己实现了,实现方式如下:
main.go
package mainimport ( "pusher")func main() { global.PusherCli= &pusher.PusherClient{ Key: "de504dc5763aeef9ff52", //数据提供商给你的key PushUrl:"ws://ws.pusherapp.com:80/app/%s?protocol=7", //pusher服务的url } errpusher := global.PusherCli.New() if errpusher != nil { panic(errpusher) } ch:=make(chan int,1) <-ch}
connection.go
package pusherimport ( "fmt" "time" "golang.org/x/net/websocket")type PusherClient struct{ Key string PushUrl string conn *websocket.Conn channels []*Channel}var PongMessgage = make(chan interface{} , 1)var IfHasMessgage = make(chan interface{} , 1)var goroutineStop bool= falsevar countReconnect intvar countGoroutine intfunc (p *PusherClient) New() ( er error) {Reconnect_Loop: log.Println("connecting") ws, err := websocket.Dial(fmt.Sprintf(p.PushUrl, p.Key), "","http://localhost/") //websocket拨号连接 if err != nil { log.Println(err) time.Sleep(time.Second * 5) countReconnect+=1 if countReconnect>1000{ log.Println("Reconnect too much") //重连次数过多 } goto Reconnect_Loop } log.Println("connected") countReconnect=0 countGoroutine+=1 if countGoroutine>1000{ //协程数过多 log.Println("Goroutine too much") } p.conn=ws p.channels=[]*Channel{} goroutineStop=false go p.poll_pong() go p.ping() var SubChannel []*Channel btcusd := p.Channel("live_trades") //订阅频道 ethusd := p.Channel("live_trades_ethusd") //订阅频道 SubChannel=append(SubChannel,btcusd) SubChannel=append(SubChannel,ethusd) go Handler(SubChannel) // handler协程处理接受到数据后的业务逻辑 return nil}func (p *PusherClient) ping() { //心跳机制 ping := NewPingMessage() for { select { case <- IfHasMessgage: case <- time.After(120*time.Second): //120秒没有接受到消息则发送ping包 {err:=websocket.JSON.Send(p.conn, ping) log.Println(ping) //fmt.Println(ping) if err!=nil{ log.Println(err) return } select { case <- PongMessgage: case <- time.After(120*time.Second): //发送ping包后120秒没有收到pong包,则重连 {go p.reconnect() return} } } } }}func (p *PusherClient) reconnect(){ //重连 goroutineStop=true err:=p.Disconnect() if err!=nil{ log.Println(err) } time.Sleep(60*time.Second) p.New()}func (p *PusherClient) poll_pong() { for { var msg Message err := websocket.JSON.Receive(p.conn, &msg)//阻塞 if err != nil { log.Println(err) return } if msg.Event == "pusher:pong" { //fmt.Println(msg) log.Println(msg) PongMessgage<-msg }else if msg.Event == "pusher:ping"{ //如果接受到server的ping包,则回应pong包 err:=websocket.JSON.Send(p.conn, NewPongMessage()) if err!=nil{ log.Println(err) return } }else{ IfHasMessgage<-msg p.processMessage(&msg) //处理消息 } }}func (p *PusherClient) processMessage(msg *Message) { for _, channel := range p.channels { if channel.Name == msg.Channel { channel.processMessage(msg) //如果接收到的消息的频道和我订阅的频道相等,则继续处理 } }}func (p *PusherClient) Disconnect() error { return p.conn.Close()}func (p *PusherClient) Channel(name string) *Channel { for _, channel := range p.channels { if channel.Name == name { return channel } } channel := NewChannel(name) p.channels = append(p.channels, channel) websocket.JSON.Send(p.conn, NewSubscribeMessage(name)) //把订阅的频道发送给pusher return channel}
message.go
package pushertype Message struct { Event string `json:"event"` Channel string `json:"channel"` Data interface{} `json:"data"`}func NewSubscribeMessage(channel string) *Message { return &Message{"pusher:subscribe", "", map[string]string{"channel": channel}}}func NewPongMessage() *Message { return &Message{"pusher:pong", "", nil}}func NewPingMessage() *Message { return &Message{"pusher:ping", "", nil}}
channel.go
package pushertype Channel struct { Name string dataChans map[string][]chan interface{}}func NewChannel(name string) *Channel { return &Channel{name, make(map[string][]chan interface{})}}func (c *Channel) Bind(event string) chan interface{} { //将事件和频道进行绑定 dataChan := make(chan interface{},10) //处理队列,缓冲10个消息 c.dataChans[event] = append(c.dataChans[event],dataChan) return dataChan}func (c *Channel) processMessage(msg *Message) { value,ok:=c.dataChans[msg.Event] if ok{ dataChan:=value[0] dataChan <- msg.Data //将消息压入管道中 }}
handler.go
package pusherfunc Handler(SubChannels []*Channel){ subChan1:= SubChannels[0].Bind("trade") //绑定事件 subchan2:= SubChannels[1].Bind("trade") for { if goroutineStop==true{ return } select { case msg,ok:=<-subChan1: //有数据则处理 if ok{ // do something } case msg,ok:=<-subchan2: //有数据则处理 if ok{ // do something } case <-time.After(5*time.Second): continue } }}
阅读全文
0 0
- pusher websocket client,基于golang
- Golang实现基于Websocket协议的H5聊天室
- Golang实现基于Websocket协议的H5聊天室(上)
- WebSocket 基于 Tomcat7.0.54 的server部署 与client访问
- Golang使用websocket
- golang websocket的例子
- golang简单实现Websocket
- Golang websocket使用方法
- golang websocket长连接
- golang websocket 失败
- golang websocket 服务器
- golang中的websocket实现
- golang websocket 入门
- WebSocket ActionScript Client
- python websocket client
- golang tcp server client
- golang kafka client
- 给golang增加websocket模块
- Virtual Box虚拟机文件瘦身处理
- Windows系统以及Mac系统/Linux系统配置环境变量
- Ansible中自定义变量的使用
- openssl 根据证书生成p7b证书链
- 【YOLO学习】召回率(Recall),精确率(Precision),平均正确率(Average_precision(AP) ),交除并(Intersection-over-Union(IoU))
- pusher websocket client,基于golang
- Spring IOC 和 AOP
- 两年小前端裸辞求职经历
- ssh框架java.lang.IllegalArgumentException
- Java中的ReadWriteLock是什么?
- MySQL 5.7.18的安装及主从复制(主从同步)
- Android软键盘输入imeOptions
- 同时启动多个tomcat 端口配置
- (详细)Hibernate查询技术(Query、Session、Criteria),Hibernate的三种状态,Hibernate集合struts2实现登录功能(二)