异步消息 Golang

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

Asynchronous messages golang

问题

我有一个使用golang编写的服务器,大致如下所示:

  1. package main
  2. func main() {
  3. for {
  4. c := listener.Accept()
  5. go handle(c)
  6. }
  7. }
  8. ...
  9. func handle(c net.Conn) {
  10. m := readMessage(c) // func(net.Conn)Message
  11. r := processMessage(m) // func(Message)Result
  12. sendResult(c, r) // func(net.Conn,Result)
  13. }

目前我需要通过一个已打开的连接异步发送消息,我知道可以使用通道,但我有点迷茫。

这是我的想法:

  1. ...
  2. func someWhereElese(c chan Result) {
  3. // 生成消息和结果
  4. r := createResultFromSomewhere()
  5. c <- r // 通过通道发送结果
  6. }

然后修改我的handle函数,使用同一个通道:

  1. func handle(c net.Conn, rc chan Result) {
  2. m := readMessage(c) // func(net.Conn)Message
  3. r := processMessage(m) // func(Message)Result
  4. rc <- r
  5. }

这就是我困惑的地方。

结果通道应该在哪里创建?在主循环中吗?

  1. func main() {
  2. ...
  3. for {
  4. c := l.Accept()
  5. rc := make(chan Result)
  6. go doSend(c, rc)
  7. }
  8. }

那读取操作呢?应该放在自己的通道/协程中吗?

如果我需要广播给n个客户端,我应该保留一个结果通道的切片吗?还是保留一个连接的切片?

我有点困惑,但我感觉我离答案很近了。

英文:

I have a golang server doing something like this:
package main

  1. func main() {
  2. for {
  3. c := listener.Accept()
  4. go handle(c)
  5. }
  6. }
  7. ...
  8. func handle(c net.Conn) {
  9. m := readMessage(c) // func(net.Conn)Message
  10. r := processMessage(m) //func(Message)Result
  11. sendResult(c, r) // func(net.Conn,Result)
  12. }

Which reads and writes messages synchronously. What I need now is to send messages asynchronously through a given open connection, I know a channel can be used by I'm kind of lost.

This is my idea:

  1. ...
  2. func someWhereElese(c chan Result) {
  3. // generate a message and a result
  4. r := createResultFromSomewhere()
  5. c &lt;- r // send the result through the channel
  6. }

And modify my handle to use that same channel instead

  1. func handle(c net.Conn, rc chan Result) {
  2. m := readMessage(c) // func(net.Conn)Message
  3. r := processMessage(m) //func(Message)Result
  4. //sendResult(c, r) // func(net.Conn,Result)
  5. rc &lt;- r
  6. }

And here's where my confusion lies.

The result channel should be created and it should have a connection where to send whatever it receives

  1. func doSend(c net.Con, rc chan Result) {
  2. r := rc // got a result channel
  3. sendResult(c, r) // send it through the wire
  4. }

But where should that channel be created? In the main loop?

  1. func main() {
  2. ...
  3. for {
  4. c := l.Accept()
  5. rc := make(chan Result)
  6. go doSend(c, rc)
  7. }
  8. }

What about the read? Should it go in it's own channel/gorutine?
If I need to broadcast to n clients, should I keep a slice of result channels? a slice of connections?

I'm kind of confused here, but I feel I'm close.

答案1

得分: 1

这个程序似乎解决了我当前的问题。

  1. package main
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "log"
  6. "net"
  7. )
  8. var rcs []chan int = make([]chan int, 0)
  9. func main() {
  10. a, e := net.ResolveTCPAddr("tcp", ":8082")
  11. if e != nil {
  12. log.Fatal(e)
  13. }
  14. l, e := net.ListenTCP("tcp", a)
  15. for {
  16. c, e := l.Accept()
  17. if e != nil {
  18. log.Fatal(e)
  19. }
  20. rc := make(chan int)
  21. go read(c, rc)
  22. go write(c, rc)
  23. rcs = append(rcs, rc)
  24. // 模拟广播
  25. log.Println(len(rcs))
  26. if len(rcs) > 5 {
  27. func() {
  28. for _, v := range rcs {
  29. log.Println("发送中")
  30. select {
  31. case v <- 34:
  32. log.Println("发送完成")
  33. default:
  34. log.Println("未发送")
  35. }
  36. }
  37. }()
  38. }
  39. }
  40. }
  41. func read(c net.Conn, rc chan int) {
  42. h := make([]byte, 2)
  43. for {
  44. _, err := c.Read(h)
  45. if err != nil {
  46. rc <- -1
  47. }
  48. var v int16
  49. binary.Read(bytes.NewReader(h[:2]), binary.BigEndian, &v)
  50. rc <- int(v)
  51. }
  52. }
  53. func write(c net.Conn, rc chan int) {
  54. for {
  55. r := <-rc
  56. o := []byte{byte(r * 2)}
  57. c.Write(o)
  58. }
  59. }

希望对你有帮助!

英文:

This program seems to solve my immediate question

  1. package main
  2. import (
  3. &quot;bytes&quot;
  4. &quot;encoding/binary&quot;
  5. &quot;log&quot;
  6. &quot;net&quot;
  7. )
  8. var rcs []chan int = make([]chan int,0)
  9. func main() {
  10. a, e := net.ResolveTCPAddr(&quot;tcp&quot;, &quot;:8082&quot;)
  11. if e != nil {
  12. log.Fatal(e)
  13. }
  14. l, e := net.ListenTCP(&quot;tcp&quot;, a)
  15. for {
  16. c, e := l.Accept()
  17. if e != nil {
  18. log.Fatal(e)
  19. }
  20. rc := make(chan int)
  21. go read(c, rc)
  22. go write(c, rc)
  23. rcs = append(rcs, rc)
  24. // simulate broacast
  25. log.Println(len(rcs))
  26. if len(rcs) &gt; 5 {
  27. func() {
  28. for _, v := range rcs {
  29. log.Println(&quot;sending&quot;)
  30. select {
  31. case v &lt;- 34:
  32. log.Println(&quot;done sending&quot;)
  33. default:
  34. log.Println(&quot;didn&#39;t send&quot;)
  35. }
  36. }
  37. }()
  38. }
  39. }
  40. }
  41. func read(c net.Conn, rc chan int) {
  42. h := make([]byte, 2)
  43. for {
  44. _, err := c.Read(h)
  45. if err != nil {
  46. rc &lt;- -1
  47. }
  48. var v int16
  49. binary.Read(bytes.NewReader(h[:2]), binary.BigEndian, &amp;v)
  50. rc &lt;- int(v)
  51. }
  52. }
  53. func write(c net.Conn, rc chan int) {
  54. for {
  55. r := &lt;-rc
  56. o := []byte{byte(r * 2)}
  57. c.Write(o)
  58. }
  59. }

huangapple
  • 本文由 发表于 2015年2月12日 04:42:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/28464098.html
匿名

发表评论

匿名网友

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

确定