我正在用 go 编写的宠物项目中设置一个 tcp 服务器。我希望能够维护所有连接的客户端的一部分,然后在新客户端连接到我的服务器或从我的服务器断开连接时修改它。
我现在的主要心理障碍是我是否应该声明一个包级切片,或者只是将一个切片传递给我的处理程序。
我的第一个想法是声明我的ClientList切片(我知道切片可能不是我最好的选择,但我决定暂时保留它)作为包级变量。虽然我认为这行得通,但我看到许多帖子不鼓励使用它们。
我的另一个想法是在我的主函数中声明ClientList为一个切片,然后我传递ClientList给我的HandleClient函数,所以每当客户端连接/断开连接时,我都可以调用AddClient或RemoveClient传递这个切片并添加/删除适当的客户端。
此实现如下所示。代码肯定还有其他问题,但我一直在努力思考一些看起来应该非常简单的事情。
type Client struct {
Name string
Conn net.Conn
}
type ClientList []*Client
// Identify is used to set the name of the client
func (cl *Client) Identify() error {
// code here to set the client's name in the based on input from client
}
// This is not a threadsafe way to do this - need to use mutex/channels
func (cList *ClientList) AddClient(cl *Client) {
*cList = append(*cList, cl)
}
func (cl *Client) HandleClient(cList *ClientList) {
defer cl.Conn.Close()
cList.AddClient(cl)
err := cl.Identify()
if err != nil {
log.Println(err)
return
}
for {
err := cl.Conn.SetDeadline(time.Now().Add(20 * time.Second))
if err != nil {
log.Println(err)
return
}
cl.Conn.Write([]byte("What command would you like to perform?\n"))
netData, err := bufio.NewReader(cl.Conn).ReadString('\n')
if err != nil {
log.Println(err)
return
}
cmd := strings.TrimSpace(string(netData))
if cmd == "Ping" {
cl.Ping() //sends a pong msg back to client
} else {
cl.Conn.Write([]byte("Unsupported command at this time\n"))
}
}
}
func main() {
arguments := os.Args
PORT := ":" + arguments[1]
l, err := net.Listen("tcp4", PORT)
if err != nil {
fmt.Println(err)
return
}
从我最初的测试来看,这似乎有效。我能够打印出我的客户列表,我可以看到正在添加新客户,并且在Identify()调用之后也添加了他们的名字。
当我使用 -race 标志运行它时,我确实收到了数据竞争警告,所以我知道我需要一种线程安全的方式来处理添加的客户端。当我添加它时删除客户端也是如此。
将我的 ClientList 传递到 中是否有任何其他问题我可能会遗漏HandleClient,或者我将 ClientList 声明为包级变量可以获得任何好处?
拉莫斯之舞
相关分类