IT虾米网

Golang 中的多线程套接字连接

十六七八 2023年11月22日 编程语言 176 0

背景

我正在使用 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 做什么。

查看一些现有的网络代码 - 在 netnet/http 库或 GitHub 上的一些流行项目中 - 看看如何编写一个很好的例子网络应用。对博客文章或教程或操作方法进行一些网络搜索,那里有很多。一定要阅读您正在使用的软件包的文档,它会对您有很大帮助。


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!