我正在尝试在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]
}
}
}
但是在这个版本中 - 发送到频道和另一端接收之间存在一些延迟,因此播放器中的视频流开始出现延迟,滞后。
也许建议使用一些软件包,或为这类任务设计模式?
感谢您的帮助!
答案 0 :(得分:0)
在频道版本中,慢速客户端也可能会增加延迟。因为慢速客户端可以使其buf_chan满,然后写入其buf_chan将阻塞。 Wrappper select可以避免它:
select {
case client.buf_chan <- buf[0:n]:
default:
//handle slow client ...
}