在golang中缓存网络流?

时间:2014-12-19 23:49:56

标签: go network-programming streaming nonblocking

我正在尝试在golang中为视频流编写缓存代理。

我的问题是,如何在多个连接之间分发大块数据的流式副本?

或者如何存储(缓存)并安全(和快速)访问多个goroutine中的数据?

我尝试了多种选项,使用互斥锁和通道,但它们无法正常工作。 这里有一些错误的样本。

这是简化版本:

...
var clients []*client
func new_client(conn net.Conn) {
    client := &client{
        conn: conn,
    }
    clients = append(clients, client)
}
...
func stream(source io.Reader) {
    buf := make([]byte, 32*1024)
    for {
        n, _ := source.Read(buf)
        for _, client := range clients {
            wn, e := client.conn.Write(buf[0:n])
            // blocks here for all clients if one of clients stops reading
        }
    }
}

此版本的问题是当一个客户端停止读取但未关闭连接时,对Write()的调用开始阻塞。在goroutine中调用Write()(在客户端使用互斥锁)没有帮助 - 与通道(下一个示例)有相同的延迟,除了不保证执行goroutine的顺序。

我试着像这样修理它:

        for _, client := range clients {
            client.conn.SetWriteDeadline(time.Now().Add(1 * time.Millisecond))
            wn, e := client.conn.Write(buf[0:n])
        }

它有助于阻止,但是慢速客户端无法及时读取,增加超时 - 返回延迟。

我也试过这样的事情:

...
var clients []*client
func new_client(conn net.Conn) {
    client := &client{
        buf_chan: make(chan []byte, 100),
    }
    clients = append(clients, client)
    for {
        buf <- client.buf_chan
        n, e := client.conn.Write(buf)
    }
}
...
func stream(source io.Reader) {
    buf := make([]byte, 32*1024)
    for {
        n, _ := source.Read(buf)
        for _, client := range clients {
            client.buf_chan <- buf[0:n]
        }
    }
}

但是在这个版本中 - 发送到频道和另一端接收之间存在一些延迟,因此播放器中的视频流开始出现延迟,滞后。

也许建议使用一些软件包,或为这类任务设计模式?

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

在频道版本中,慢速客户端也可能会增加延迟。因为慢速客户端可以使其buf_chan满,然后写入其buf_chan将阻塞。 Wrappper select可以避免它:

select {
case client.buf_chan <- buf[0:n]:
default:
//handle slow client ...    
}