2016-05-09 75 views
0

所以,我试图构建一个websocket服务器。我遇到了这个有趣的bug,我不知道为什么它会发生。GO - 函数返回后代码停止执行

注:评论代码片段在那里只为这个​​职位。 阅读它们

Ive得到了这样的功能:

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 
      } 
     } 
    } 
} 
+0

'Messages {}'输出在哪里?我没有看到它在某处实施 –

+0

@SimoEndre现在如何?我设法粘贴错误的代码片段。 – Olian04

+0

看看大头钉的痕迹,看看每个goroutine被阻挡的位置 – JimB

回答

2

纵观Listen功能,您将此话意味着它有一个接受的Message{}结构一个Messages渠道,但在主要的goroutine它不会输出。请记住,goroutines是双向沟通渠道,这意味着如果渠道确实收到一个输入值,它必须有一个输出值,渠道不会阻止。

所以,你需要用相同的结构类型为Message{}

message := make(chan Message{}) 

然后你必须跳出价值加入功能创建一个通道推到通道:

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

在新输入后更新

迭代来自频道的值是不够的,您n在go func()内部做到这一点。

从关键字select关键字中获取不同的同时执行的goroutines的值,这个关键字非常类似于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方法是如何实现的,但是,如果这个想法是接收通道值推到你不得不修改代码的方式,以通道值发送回堆栈阵列。在上面的代码片段中,我只是想强调重要的是将值推回到频道中。

+0

感谢您的回应,为了澄清我的问题,Ive稍微改变了原文。 – Olian04

+0

我想你错过了整个问题,代码的每个部分都起作用,除了我提到的那个。 例如。 MessageHandler和Push都按预期工作。他们都使用go例程(如我在帖子中所述)。 事情是:渠道不是这里的问题。我之前在程序的另一部分使用过它,它工作得很好。 另外:如果您查看提供的代码,Listen(...)结尾处的fmt.Println(...)确实会被调用,但函数调用之后的fmt.Println(...)听(...)不。 (我在原帖中标记了他们) – Olian04

+2

@ Olian04 - 由于监听块*,代码不会在监听后调用。您需要根据此答案处理阻止行为。 – elithrar