2015-02-11 2 views
0

У меня есть сервер golang делать что-то вроде этого: пакета главногоАсинхронных сообщений golang

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) { 
    // generate a message and a result 
    r := createResultFromSomewhere() 
    c <- r // send the result through the channel 
} 

И изменить мою ручку, чтобы использовать тот же канал вместо

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 
} 

А вот где моя путаница лежит.

В результате канал должен быть создан, и он должен иметь соединение, куда послать то, что он получает

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

Но где должен быть создан этот канал? В основном цикле?

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

А как насчет прочитанного? Должен ли он пойти в собственный канал/горутин? Если мне нужно транслировать до n клиентов, должен ли я хранить кусок результирующих каналов? кусок соединений?

Я здесь немного смущен, но я чувствую, что я рядом.

+0

Начало здесь: http://talks.golang.org/2012/concurrency.slide. Ключ к вашей проблеме заключается в использовании 'select' для просмотра входящего канала соединения, канала ответа и, возможно, выхода из канала. В зависимости от вашей ожидаемой загрузки создание одного goroutine за запрос может быть прекрасным; или вам может понадобиться создать пул. Но вы поймете правильные вопросы лучше, как только пройдете Шаблоны параллелизма. См. Также http://blog.golang.org/advanced-go-concurrency-patterns и особенно «связанные статьи» в конце. Понимание 'select' является одним из великих« о, вот как работает Go! » моменты. –

+0

@RobNapier Uhm ... Я читал слайды раньше, и я вроде как получаю их, но не совсем. Через несколько мгновений я снова пройду через них. Между тем у меня была небольшая программа, можете ли вы прокомментировать ее, если увидите что-то особенно опасное? – OscarRyz

+0

OK; Возможно, я неправильно понял, что вы подразумеваете под «асинхронным». Я предположил, что несколько запросов и ответов будут выполняться по одному и тому же соединению (запросы чередования). Вы, похоже, имеете в виду, что хотите передавать данные, как читатель получает. Это, возможно, немного параллельнее, чем просто чтение двух байтов и запись двух байтов в одном goroutine. Вы можете посмотреть на 'golang.org/x/text/transform' для этой цели вместе с' io.Copy() '. (Извините, я не более полезен с реальным кодом здесь, это был интересный вопрос, но у меня нет времени в эту минуту, чтобы помочь экстенсивно). –

ответ

0

Эта программа, кажется, решить мой непосредственный вопрос

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) 
    } 
} 
Смежные вопросы