OscarRyz
OscarRyz

Reputation: 199333

Asynchronous messages golang

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.

Upvotes: 0

Views: 2806

Answers (1)

OscarRyz
OscarRyz

Reputation: 199333

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)
    }
}

Upvotes: 1

Related Questions