2016-05-09 74 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