前言:单向的流式传输,也被称为服务器推送(Server Push),在当前业务中运用是实时消息推送,比如社交网络的实时消息、邮件通知、实时新闻更新等。服务器可以在有新的消息时立即推送到客户端,而不需要客户端定期轮询服务器。
本案例采用了gin的官方示例实现,实际运用上可能还需要一定完善
定义了一个Event结构体,它包含了以下几个字段:
- Message: 一个字符串类型的通道,用于接收主程序发送的事件消息。
- NewClients: 一个ClientChan类型的通道,用于接收新连接的客户端通道。
- ClosedClients: 一个ClientChan类型的通道,用于接收关闭连接的客户端通道。
- TotalClients: 一个以ClientChan为键,布尔值为值的映射,用于存储所有当前连接的客户端通道。
type Event struct {
// Events are pushed to this channel by the main events-gathering routine
Message chan string
// New client connections
NewClients chan chan string
// Closed client connections
ClosedClients chan chan string
// Total client connections
TotalClients map[chan string]bool
}
ClientChan是一个字符串类型的别名,表示客户端通道。
// New event messages are broadcast to all registered client connection channels
type ClientChan chan string
定义了一个NewServer函数,它返回一个Event指针,主要功能是:
- 使用make函数初始化Event结构体中的各个字段。
- 启动一个协程,调用Event结构体的listen方法监听各个通道上的消息,并进行相应的处理。
- 返回Event结构体的指针。
// Initialize event and Start procnteessing requests
func NewServer() (event *Event) {
//使用make函数初始化Event结构体中的各个字段。
event = &Event{
Message: make(chan string),
NewClients: make(chan chan string),
ClosedClients: make(chan chan string),
TotalClients: make(map[chan string]bool),
}
//启动一个协程,调用Event结构体的listen方法监听各个通道上的消息,并进行相应的处理。
go event.listen()
return
}
定义了一个listen方法,它属于Event结构体。
- 使用for循环和select语句不断地等待各个通道上的消息。
- 当收到NewClients通道上的消息时,表示有新客户端连接到服务器。将该客户端通道添加到TotalClients映射中,并打印日志信息。
- 当收到ClosedClients通道上的消息时,表示有客户端断开连接。将该客户端通道从TotalClients映射中删除,并关闭该通道,并打印日志信息。
- 当收到Message通道上的消息时,表示有新事件消息需要广播。遍历TotalClients映射中的所有客户端通道,并将事件消息发送给它们。
func (stream *Event) listen() {
for {
select {
// 添加新的客户端
case client := <-stream.NewClients:
stream.TotalClients[client] = true
log.Printf("Client added. %d registered clients", len(stream.TotalClients))
// 删除已经关闭的客户端
case client := <-stream.ClosedClients:
delete(stream.TotalClients, client)
close(client)
log.Printf("Removed client. %d registered clients", len(stream.TotalClients))
// Broadcast message to client
case eventMsg := <-stream.Message:
for clientMessageChan := range stream.TotalClients {
clientMessageChan <- eventMsg
}
}
}
}