我想收听多个传输编码响应的HTTP流,然后逐行从中获取消息,然后将消息推送到一个通道。我想从通道读取并稍后通过websocket。
func subscribe(ws chan<- string, group string) (scanner *bufio.Scanner, err error){
res, _ := req(STREAM_URL, channelTemplate(group))
reader := bufio.NewScanner(res.Body)
return reader, reader.Err()
}
func main() {
ws := make(chan string)
request, _ := http.NewRequest("GET", URL, nil)
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
resp, _ := client.Do(request)
ac := ACResponse{}
json.NewDecoder(resp.Body).Decode(&ac)
resp.Body.Close()
var scanners = make([]*bufio.Scanner, 0)
for _, group := range ac.Groups {
fmt.Println("Started worker for", group)
//listen to all stream URLs
scanner, err := subscribe(ws, group)
if err != nil {
panic(err)
}
// keep track of Scanner to read later
scanners = append(scanners, scanner)
}
for {
select {
case msg := <-ws:
fmt.Println("[events] ", msg)
default:
randScanner := rand.Intn(len(ac.Groups)-1)
fmt.Println("Reading from", randScanner)
reader := scanners[randScanner]
reader.Scan()
if err := reader.Err(); err != nil {
panic(err)
}
text := reader.Text()
ws <- text
}
}
}
该程序在reader.Scan()
处阻止。输出为Reading from 1
,没有别的。我看着wireshark,消息传来。
如何使用Go更好地设计此问题?
答案 0 :(得分:0)
发送到无缓冲通道ws
的主要块。要解决此问题,请将ws
更改为缓冲频道:
ws := make(chan string, 1)
第二个问题是main()在达到EOF后继续读取扫描仪。问题出在以下几个方面:
reader.Scan()
if err := reader.Err(); err != nil {
panic(err)
}
text := reader.Text()
Scan()在EOF返回false,但忽略扫描返回。 Err()在EOF上返回nil。修改应用程序以使用Scan()的返回值。
另一个问题是读取任何一个扫描仪的主要块。为避免阻塞单个连接,请启动goroutine以读取每个连接:
func subscribe(wg *sync.WaitGroup, ws chan<- string, group string) {
defer wg.Done()
res, err := req(STREAM_URL, channelTemplate(group))
if err ! nil {
// handle error
}
defer resp.Body.Close()
reader := bufio.NewScanner(res.Body)
for reader.Scan() {
ws <- reader.Text()
}
if err := reader.Err(); err != nil {
// handle error
}
}
func main() {
ws := make(chan string)
request, _ := http.NewRequest("GET", URL, nil)
request.Header.Add("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(request)
if err != nil {
// handle error
}
var ac ACResponse
if err := json.NewDecoder(resp.Body).Decode(&ac); err != nil {
// handle error
}
resp.Body.Close()
var wg sync.WaitGroup
for _, group := range ac.Groups {
wg.Add(1)
go subscribe(&wg, ws, group)
}
go func() {
wg.Wait()
close(ws)
}()
for msg := range ws {
fmt.Println("[events] ", msg)
}
}
以上代码未经编译且未经测试。我已经标记了需要进行错误处理的位置。所有连接到达EOF后,我编写代码退出main。这可能是你想要的,也可能不是你想要的。