背景
我正在使用 Golang 创建一个聊天室服务器。每次客户端连接到服务器时,我都会将客户端函数作为一个新线程启动,这样每个客户端都会得到一个被监听的线程。我能够基于 this tutorial 创建一个简单的客户端服务器连接,但现在我正在尝试为多个客户端创建连接,以便他们可以向聊天室发送消息。
代码解释
关注this tutorial ,看起来我可以使用 go func()
创建线程并等待通过包含 channel ( <-newClient
) 建立连接。我在调用用户函数之前将一个 bool 值传递到 channel 中,因为用户函数将永远运行并且我想建立其他客户端连接。每个客户端连接都将运行用户函数。
问题
我不知道如何将用户连接变量传递给我的其他函数。我正在放置 conn net
在我的函数的参数中,但这只是一个占位符,因为我不确定这样做的正确方法。
此外,我的 go func()
在 channel 实现之后调用 user() 是我对多线程的最佳尝试,但我不确定我的考虑是否正确。
Server.go
package main
import (
"net"
"fmt"
"bufio"
"strings"
"container/list"
"time"
)
type chatRoom struct {
name string
messages list.List
users list.List
lastUsed time.Time
}
var chatRooms *list.List //A list of chatrooms where each client can post messages, where messages can be seen by all clients in the chatroom
var conn net.Conn
func user(conn net) {
for {
message, _ := bufio.NewReader(conn).ReadString('\n') // will listen for message to process ending in newline (\n)
fmt.Print("Message Received:", string(message)) // output message received
s := strings.Split(string(message), ":")
if strings.Compare(s[0],"create") == 0{ //create a chat room
create(conn, s[1])
}else if strings.Compare(s[0],"list") == 0 { //List the current chatrooms
msg = listRooms(conn)
}else if strings.Compare(s[0],"join") == 0 { //Join the user to a chat room
join(conn, s[1])
}else if strings.Compare(s[0],"leave") == 0 { //Remove the user from a chatroom
leave(conn, s[1])
}else if strings.Compare(s[0],"message") == 0{ //Send a message to a chatroom
message(conn, s[1], s[2])
}
}
}
func main() {
fmt.Println("Launching server...")
this.userList = list.New()
this.chatRooms = list.New();
ln, _ := net.Listen("tcp", ":8081") // listen on all interfaces
conn, _ := ln.Accept() // accept connection on port
for { // run loop forever (or until ctrl-c)
go func(){
newClient := make(chan bool)
ln, _ := net.Listen("tcp", ":8081") // listen on all interfaces
conn, _ := ln.Accept() // accept connection on port
newClient <- true
user(conn)
}
<-newClient
}
}
请您参考如下方法:
理解这里的区别非常重要:这是并发,而不是多线程,这些是goroutines,而不是线程。这些概念不可互换。至于您的核心问题,您的实现存在一些重大问题:
- 您正在启动一个 goroutine 关闭 跨循环迭代共享的变量,关键是
conn
。每次接受连接时,都会覆盖每个 goroutine 共享的conn
。您应该将conn
传递 给您的 goroutine,这样它就有自己的本地副本,或者在每次循环迭代中创建一个新的conn
变量,而不是重复使用一个。 - 您在每个循环迭代中启动一个新的监听器,这将失败,因为旧的监听器仍在使用该端口。您不需要新的听众。只需在现有监听器上继续调用
ln.Accept
即可继续接受新连接。查看文档介绍net
package ,或检查 在 Go 中使用监听器的任何代码 作为示例。 - 您正在 goroutine 内部创建
newClient
,然后尝试在 goroutine 外部引用它。这甚至不会编译,并且不清楚您首先要尝试使用此 channel 做什么。
查看一些现有的网络代码 - 在 net
或 net/http
库或 GitHub 上的一些流行项目中 - 看看如何编写一个很好的例子网络应用。对博客文章或教程或操作方法进行一些网络搜索,那里有很多。一定要阅读您正在使用的软件包的文档,它会对您有很大帮助。