Golang Gorilla Websocket在120秒后停止接收信息。

huangapple go评论81阅读模式
英文:

Golang Gorilla Websocket stops receiving information at 120 seconds

问题

我目前正在尝试连接到CEX.IO比特币交易所的WebSocket,但不仅与CEX.IO有问题,还与其他交易所也有问题。所有的连接在大约120秒的时候都会断开,这让我觉得可能存在某种TTL问题。主包中的Process() goroutine最终只是挂起并等待来自readLoop的数据,而readLoop则停止接收数据。我在代码中包含了一些只读API密钥,你可以测试一下。

以下是连接到cexio WebSocket的代码。这是他们API的链接:https://cex.io/websocket-api

package cexio

import (
  "github.com/gorilla/websocket"
  "github.com/satori/go.uuid"
  "encoding/hex"
  "encoding/json"
  "crypto/hmac"
  "crypto/sha256"
  "bytes"
  "strconv"
  "time"
  "fmt"
)

const Url = "wss://ws.cex.io/ws/"

type Connection struct {
  conn *websocket.Conn
}

type IntraAppMessage struct {
  SocketMessage   GenericMessage
  ProgramMessage  ProgramMessage
}

type GenericMessage struct {
  Event   string      `json:"e"`
  Data    interface{} `json:"data"`
  Auth    AuthData    `json:"auth,omitempty"`
  Ok      string      `json:"ok,omitempty"`
  Oid     string      `json:"oid,omitempty"`
  Time    int64       `json:"time,omitempty"`
}

type ProgramMessage struct {
  Error   string
}

type AuthData struct {
  Key       string  `json:"key"`
  Signature string  `json:"signature"`
  Timestamp int64   `json:"timestamp"`
}

type OrderBookSubscribeData struct {
  Pair      [2]string   `json:"pair"`
  Subscribe bool        `json:"subscribe"`
  Depth     int         `json:"depth"`
}

func (c *Connection) SendPong() error {

  pongMsg := GenericMessage{
    Event: "pong",
  }

  err := c.conn.WriteJSON(pongMsg)
  if err != nil {
    return nil
  }

  deadline := time.Now().Add(15*time.Second)

  err = c.conn.WriteControl(websocket.PongMessage, nil, deadline)
  if err != nil {
    return err
  }

  return nil

}

func (c *Connection) SendPing() error {

  pingMsg := GenericMessage{
    Event: "get-balance",
    Oid: uuid.NewV4().String(),
  }

  err := c.conn.WriteJSON(pingMsg)
  if err != nil {
    return err
  }

  deadline := time.Now().Add(15*time.Second)

  err = c.conn.WriteControl(websocket.PingMessage, nil, deadline)
  if err != nil {
    return err
  }

  return nil

}

func (c *Connection) Connect() error {
  dialer := *websocket.DefaultDialer
  wsConn, _, err := dialer.Dial(Url, nil)
  if err != nil {
    return err
  }

  c.conn = wsConn

  for {

    _, msgBytes, err := c.conn.ReadMessage()
    if err != nil {
      c.Disconnect()
      return err
    }

    fmt.Println(string(msgBytes))

    var m GenericMessage
    err = json.Unmarshal(msgBytes, &m)
    if err != nil {
      c.Disconnect()
      return err
    }

    if m.Event != "connected" {
      c.Disconnect()
      return err
    } else {
      break
    }

  }

  return nil
}

func (c *Connection) Disconnect() error {
  return c.conn.Close()
}

func (c *Connection) ReadLoop(ch chan<- IntraAppMessage) {
  for {

    fmt.Println("starting new read")

    _, msgBytes, err := c.conn.ReadMessage()
    if err != nil {
      ch <- IntraAppMessage{
        ProgramMessage: ProgramMessage{
          Error: err.Error(),
        },
      }
      continue
    }

    var m GenericMessage
    err = json.Unmarshal(msgBytes, &m)
    if err != nil {
      ch <- IntraAppMessage{
        ProgramMessage: ProgramMessage{
          Error: err.Error(),
        },
      }
      continue
    }

    ch <- IntraAppMessage{
      SocketMessage: m,
    }

  }
}

func CreateSignature(timestamp int64, key, secret string) string {
  secretBytes := []byte(secret)
  h := hmac.New(sha256.New, secretBytes)

  var buffer bytes.Buffer
  buffer.WriteString(strconv.FormatInt(timestamp, 10))
  buffer.WriteString(key)

  h.Write(buffer.Bytes())

  return hex.EncodeToString(h.Sum(nil))
}

func (c *Connection) Authenticate(key, secret string) error {

  timestamp := time.Now().Unix()
  signature := CreateSignature(timestamp, key, secret)

  var authMsg GenericMessage
  authMsg.Event = "auth"
  authMsg.Auth = AuthData{
    Key: key,
    Signature: signature,
    Timestamp: timestamp,
  }

  err := c.conn.WriteJSON(authMsg)
  if err != nil {
    return err
  }

  for {
    _, msgBytes, err := c.conn.ReadMessage()
    if err != nil {
      c.Disconnect()
      return err
    }

    fmt.Println(string(msgBytes))

    var m GenericMessage
    err = json.Unmarshal(msgBytes, &m)
    if err != nil {
      c.Disconnect()
      return err
    }

    if m.Event != "auth" && m.Ok != "ok" {
      c.Disconnect()
      return err
    } else {
      break
    }
  }

  return nil

}

func (c *Connection) SubscribeToOrderBook(pair [2]string) error {

  sendMsg := GenericMessage{
    Event: "order-book-subscribe",
    Data: OrderBookSubscribeData{
      Pair: pair,
      Subscribe: true,
      Depth: 0,
    },
    Oid: uuid.NewV4().String(),
  }

  err := c.conn.WriteJSON(sendMsg)
  if err != nil {
    return err
  }

  return nil

}

func (c *Connection) GetBalance() error {

  sendMsg := GenericMessage{
    Event: "get-balance",
    Oid: uuid.NewV4().String(),
  }

  err := c.conn.WriteJSON(sendMsg)
  if err != nil {
    return err
  }

  return nil

}

希望对你有所帮助!

英文:

I'm currently trying to connect to the CEX.IO bitcoin exchange's websocket, but have been having issues not only with CEX.IO but with others too. All of my connections drop around the 120-second mark which makes me think there is some TTL problem going on. The Process() goroutine in the main package ends up just hanging and waiting for data from the readLoop which just stops receiving data. I've included some read-only API keys in the code so you can test if you'd like.

package main
import (
&quot;fmt&quot;
&quot;bitbucket.org/tradedefender/cryptocurrency/exchange-connector/cexio&quot;
&quot;github.com/shopspring/decimal&quot;
&quot;encoding/json&quot;
&quot;time&quot;
)
type OrderBook struct {
Asks []Ask
Bids []Bid
}
type Ask struct {
Rate    decimal.Decimal
Amount  decimal.Decimal
}
type Bid struct {
Rate    decimal.Decimal
Amount  decimal.Decimal
}
func main() {
cexioConn := new(cexio.Connection)
err := cexioConn.Connect()
if err != nil {
fmt.Errorf(&quot;error: %s&quot;, err.Error())
}
err = cexioConn.Authenticate(&quot;TLwYkktLf7Im6nqSKt6UO1IrU&quot;, &quot;9ImOJcR7Qj3LMIyPCzky0D7WE&quot;)
if err != nil {
fmt.Errorf(&quot;error: %s&quot;, err.Error())
}
readChannel := make(chan cexio.IntraAppMessage, 25)
go cexioConn.ReadLoop(readChannel)
processor := Processor{
WatchPairs: [][2]string{
[2]string{
&quot;BTC&quot;, &quot;USD&quot;,
},
},
conn: cexioConn,
}
go processor.Process(readChannel)
// LOL
for {
continue
}
}
type Processor struct {
WatchPairs [][2]string
conn *cexio.Connection
}
func (p *Processor) Process(ch &lt;-chan cexio.IntraAppMessage) {
p.conn.SubscribeToOrderBook(p.WatchPairs[0])
pingTimer := time.Now().Unix()
for {
fmt.Printf(&quot;(%v)\n&quot;, time.Now().Unix())
if (time.Now().Unix() - pingTimer) &gt;= 10 {
fmt.Println(&quot;sending ping&quot;)
p.conn.SendPing()
pingTimer = time.Now().Unix()
}
readMsg := &lt;- ch
output, _ := json.Marshal(readMsg.SocketMessage)
fmt.Println(string(output))
if readMsg.SocketMessage.Event == &quot;ping&quot; {
fmt.Println(&quot;sending pong&quot;)
p.conn.SendPong()
pingTimer = time.Now().Unix()
}
}
}

Below is the connector to the cexio websocket. Here is a link to their API: https://cex.io/websocket-api

package cexio
import (
&quot;github.com/gorilla/websocket&quot;
//&quot;github.com/shopspring/decimal&quot;
&quot;github.com/satori/go.uuid&quot;
&quot;encoding/hex&quot;
&quot;encoding/json&quot;
&quot;crypto/hmac&quot;
&quot;crypto/sha256&quot;
&quot;bytes&quot;
&quot;strconv&quot;
&quot;time&quot;
&quot;fmt&quot;
)
const Url = &quot;wss://ws.cex.io/ws/&quot;
type Connection struct {
conn *websocket.Conn
}
type IntraAppMessage struct {
SocketMessage   GenericMessage
ProgramMessage  ProgramMessage
}
type GenericMessage struct {
Event   string      `json:&quot;e&quot;`
Data    interface{} `json:&quot;data&quot;`
Auth    AuthData    `json:&quot;auth,omitempty&quot;`
Ok      string      `json:&quot;ok,omitempty&quot;`
Oid     string      `json:&quot;oid,omitempty&quot;`
Time    int64       `json:&quot;time,omitempty&quot;`
}
type ProgramMessage struct {
Error   string
}
type AuthData struct {
Key       string  `json:&quot;key&quot;`
Signature string  `json:&quot;signature&quot;`
Timestamp int64   `json:&quot;timestamp&quot;`
}
type OrderBookSubscribeData struct {
Pair      [2]string   `json:&quot;pair&quot;`
Subscribe bool        `json:&quot;subscribe&quot;`
Depth     int         `json:&quot;depth&quot;`
}
func (c *Connection) SendPong() error {
pongMsg := GenericMessage{
Event: &quot;pong&quot;,
}
err := c.conn.WriteJSON(pongMsg)
if err != nil {
return nil
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PongMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) SendPing() error {
pingMsg := GenericMessage{
Event: &quot;get-balance&quot;,
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(pingMsg)
if err != nil {
return err
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PingMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) Connect() error {
dialer := *websocket.DefaultDialer
wsConn, _, err := dialer.Dial(Url, nil)
if err != nil {
return err
}
c.conn = wsConn
//c.conn.SetPingHandler(c.HandlePing)
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &amp;m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != &quot;connected&quot; {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) Disconnect() error {
return c.conn.Close()
}
func (c *Connection) ReadLoop(ch chan&lt;- IntraAppMessage) {
for {
fmt.Println(&quot;starting new read&quot;)
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
ch &lt;- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
var m GenericMessage
err = json.Unmarshal(msgBytes, &amp;m)
if err != nil {
ch &lt;- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
ch &lt;- IntraAppMessage{
SocketMessage: m,
}
}
}
func CreateSignature(timestamp int64, key, secret string) string {
secretBytes := []byte(secret)
h := hmac.New(sha256.New, secretBytes)
var buffer bytes.Buffer
buffer.WriteString(strconv.FormatInt(timestamp, 10))
buffer.WriteString(key)
h.Write(buffer.Bytes())
return hex.EncodeToString(h.Sum(nil))
}
func (c *Connection) Authenticate(key, secret string) error {
timestamp := time.Now().Unix()
signature := CreateSignature(timestamp, key, secret)
var authMsg GenericMessage
authMsg.Event = &quot;auth&quot;
authMsg.Auth = AuthData{
Key: key,
Signature: signature,
Timestamp: timestamp,
}
err := c.conn.WriteJSON(authMsg)
if err != nil {
return err
}
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &amp;m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != &quot;auth&quot; &amp;&amp; m.Ok != &quot;ok&quot; {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) SubscribeToOrderBook(pair [2]string) error {
sendMsg := GenericMessage{
Event: &quot;order-book-subscribe&quot;,
Data: OrderBookSubscribeData{
Pair: pair,
Subscribe: true,
Depth: 0,
},
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}
func (c *Connection) GetBalance() error {
sendMsg := GenericMessage{
Event: &quot;get-balance&quot;,
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}

答案1

得分: 0

解决方法是在主函数的末尾删除以下代码:

for { 
continue 
}
英文:

Solution was to remove the

for { 
continue 
}

at the end of the main function

huangapple
  • 本文由 发表于 2017年3月24日 23:39:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/43003683.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定