英文:
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 <- 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 <- 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 (
"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)
// simulate broacast
log.Println(len(rcs))
if len(rcs) > 5 {
func() {
for _, v := range rcs {
log.Println("sending")
select {
case v <- 34:
log.Println("done sending")
default:
log.Println("didn't send")
}
}
}()
}
}
}
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论