1 回答
TA贡献1820条经验 获得超10个赞
这种方法存在几个问题。
首先,您的代码包含数据竞争:每个 TCP 连接都由一个单独的 goroutine 提供服务,并且它们都试图同时修改切片。
go build -race您可能会尝试使用(或go install -race— 无论您使用什么)构建代码,并看到它因启用的运行时检查而崩溃。
这个很容易修复。最直接的方法是在类型中添加一个互斥变量ClientList:
type ClientList struct {
mu sync.Mutex
clients []*Client
}
…并使类型的方法在改变字段时保持互斥量clients,如下所示:
func (cList *ClientList) AddClient(cl *Client) {
cList.mu.Lock()
defer cList.mu.Unlock()
cList.clients = append(cList.clients, o)
}
(如果你曾经遇到过你的ClientList类型的典型使用模式是频繁调用只读取包含列表的方法,你可以开始使用sync.RWLock允许多个并发读取器的类型。)
其次,我将“识别”客户端的部分从处理函数中分离出来。至此,在handler中,如果识别失败,handler退出,但client不会退市。
我会说最好预先识别它,并且只有在认为客户没问题时才运行处理程序。
此外,值得RemoveClient在处理程序主体的顶部添加一个延迟调用,以便在处理程序完成时正确地取消列出客户端。
IOW,我希望看到这样的事情:
func (cl *Client) HandleClient(cList *ClientList) {
defer cl.Conn.Close()
err := cl.Identify()
if err != nil {
log.Println(err)
return
}
cList.AddClient(cl)
defer cList.RemoveClient(cl)
// ... the rest of the code
}
- 1 回答
- 0 关注
- 99 浏览
添加回答
举报