GO - 函数返回后代码停止执行

时间:2016-05-09 11:06:56

标签: go websocket

所以,我正在尝试构建一个websocket服务器。我遇到了这个有趣的错误,我不知道为什么会发生这种错误。

注意: 代码段中的评论仅适用于此帖子。 阅读

我有这个功能:

func Join(ws *websocket.Conn) {
    Log.Connection(ws)

    enc := json.NewEncoder(ws)
    dec := json.NewDecoder(ws)

    var dJ g.DiscussionJoin
    var disc g.Discussion

    Log.Err(dec.Decode(&dJ), "dec.Decode")

    ssD := g.FindDiscussionByID(dJ.DiscussionID)

    ssDJ := dJ.Convert(ws)

    g.DiscHandle <- &ssDJ

    disc = ssD.Convert()

    Log.Err(enc.Encode(disc), "enc.Encode")

    Log.Activity("Discussion", "Joined", disc.DiscussionID.Subject)

    fmt.Println("Listening") //This gets called
    g.Listen(dec)
    fmt.Println("Stoped Listening") //This DOESN'T get called [IT SHOULD]

    ssDJ.SSDiscussion.Leave(ssDJ.SSUserID)

    Log.Disconnection(ws)
}

造成这种情况的功能是(在我看来)g.Listen(...):

func Listen(dec *json.Decoder) {
    timeLastSent := time.Now().Second()
    in := Message{}
    for ((timeLastSent + ConnTimeout) % 60) != time.Now().Second() {
        if err := dec.Decode(&in); err != nil {
            continue
        } else if in == Ping {
            timeLastSent = time.Now().Second()
            continue
        }
        timeLastSent = time.Now().Second()
        Messages <- in
        in = Message{}
    }
    fmt.Println("Client timed out!") //This gets called
    return
}

我已经在收听

的最后一行使用和不使用返回进行了尝试

作为对@SimoEndre的响应,我将主方法从代码示例中删除了,但是既然你提到了它,那么这就是将g.Messege {}带出Messeges通道的函数。
注意: MessageHandler()在自己的例程中运行。

func MessageHandler() {
    for msg := range Messages {
        for _, disc := range LivingDiscussions {
            if disc.DiscussionID.UDID == msg.UDID {
                go disc.Push(msg)
                break
            }
        }
    }
}

1 个答案:

答案 0 :(得分:2)

查看Listen函数,您会注意到它有一个Messages通道,它接收Message{}结构,但在主goroutine中它不会输出。请记住,goroutine是双向通信通道,这意味着如果通道确实接收到输入值,它必须具有不阻塞通道的输出值。

因此,您需要创建一个与Message{}

具有相同结构类型的通道
message := make(chan Message{})

然后在Join函数中,你必须弹出推送到channel:

的值
func Join(ws *websocket.Conn) {
    ...
    <-message
}

新输入后更新

不足以迭代来自频道的值,您需要在go func()内执行此操作。

可以使用select关键字从不同的并发执行goroutine中获取值,该关键字与switch控制语句非常相似,有时也称为通信开关。

go func() {   
    for msg := range Messages {
        for _, disc := range LivingDiscussions {
            if disc.DiscussionID.UDID == msg.UDID {
                select {
                case disc.Push <- msg: // push the channel value to the stack

                default :
                // default action
                }
            }
        }
    }
}()

我不知道您的disc.Push方法是如何实现的,但如果想要将收到的通道值推送到堆栈,您必须修改代码以回发通道值到阵列。在上面的代码片段中,我只想强调将值重新推入频道非常重要。