异步消息 Golang

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

Asynchronous messages golang

问题

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

package main

func main() {
    for {
        c := listener.Accept()
        go handle(c)
    }
}

...

func handle(c net.Conn) {
    m := readMessage(c)    // func(net.Conn)Message
    r := processMessage(m) // func(Message)Result
    sendResult(c, r)       // func(net.Conn,Result)
}

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

这是我的想法:

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

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

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

这就是我困惑的地方。

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

func main() {
    ...
    for {
        c := l.Accept()
        rc := make(chan Result)
        go doSend(c, rc)
    }
}

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

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

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

英文:

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

func main() {
	for {
		c := listener.Accept()
		go handle(c)
	}
}

...
func handle(c net.Conn) {
	m := readMessage(c)    // func(net.Conn)Message
	r := processMessage(m) //func(Message)Result
	sendResult(c, r)       // func(net.Conn,Result)
}

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:

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

And modify my handle to use that same channel instead

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

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

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

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

func main() {
    ...
	for {
		c := l.Accept()
		rc := make(chan Result)
		go doSend(c, rc)
	}
}

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

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

package main

import (
	"bytes"
	"encoding/binary"
	"log"

	"net"
)

var rcs []chan int = make([]chan int, 0)

func main() {
	a, e := net.ResolveTCPAddr("tcp", ":8082")
	if e != nil {
		log.Fatal(e)
	}
	l, e := net.ListenTCP("tcp", a)
	for {
		c, e := l.Accept()
		if e != nil {
			log.Fatal(e)
		}
		rc := make(chan int)
		go read(c, rc)
		go write(c, rc)
		rcs = append(rcs, rc)
		// 模拟广播
		log.Println(len(rcs))
		if len(rcs) > 5 {
			func() {
				for _, v := range rcs {
					log.Println("发送中")
					select {
					case v <- 34:
						log.Println("发送完成")
					default:
						log.Println("未发送")
					}
				}
			}()
		}
	}
}

func read(c net.Conn, rc chan int) {
	h := make([]byte, 2)
	for {
		_, err := c.Read(h)
		if err != nil {
			rc <- -1
		}
		var v int16
		binary.Read(bytes.NewReader(h[:2]), binary.BigEndian, &v)
		rc <- int(v)
	}
}

func write(c net.Conn, rc chan int) {
	for {
		r := <-rc
		o := []byte{byte(r * 2)}
		c.Write(o)
	}
}

希望对你有帮助!

英文:

This program seems to solve my immediate question

package main
import (
&quot;bytes&quot;
&quot;encoding/binary&quot;
&quot;log&quot;
&quot;net&quot;
)
var rcs []chan int = make([]chan int,0)
func main() {
a, e := net.ResolveTCPAddr(&quot;tcp&quot;, &quot;:8082&quot;)
if e != nil {
log.Fatal(e)
}
l, e := net.ListenTCP(&quot;tcp&quot;, a)
for {
c, e := l.Accept()
if e != nil {
log.Fatal(e)
}
rc := make(chan int)
go read(c, rc)
go write(c, rc)
rcs = append(rcs, rc)
// simulate broacast
log.Println(len(rcs))
if len(rcs) &gt; 5 {
func() {
for _, v := range rcs {
log.Println(&quot;sending&quot;)
select {
case v &lt;- 34:
log.Println(&quot;done sending&quot;)
default:
log.Println(&quot;didn&#39;t send&quot;)
}
}
}()
}
}
}
func read(c net.Conn, rc chan int) {
h := make([]byte, 2)
for {
_, err := c.Read(h)
if err != nil {
rc &lt;- -1
}
var v int16
binary.Read(bytes.NewReader(h[:2]), binary.BigEndian, &amp;v)
rc &lt;- int(v)
}
}
func write(c net.Conn, rc chan int) {
for {
r := &lt;-rc
o := []byte{byte(r * 2)}
c.Write(o)
}
}

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:

确定