Golang中的多线程套接字连接

时间:2018-12-31 03:56:13

标签: multithreading go

背景

我正在使用Golang创建聊天室服务器。每次客户端连接到服务器时,我都将Client函数作为新线程启动,以便每个客户端都获得一个被监听的线程。我能够基于this tutorial创建一个简单的客户端服务器连接,但是现在我正在尝试为多个客户端创建连接,以便它们可以将消息发送到聊天室。

代码说明

this tutorial之后,看来我可以使用go func()创建线程,并等待包含通道(<-newClient)的建立。在调用用户函数之前,我将bool值传递给通道,因为用户函数将永远运行,并且我想建立其他客户端连接。每个客户端连接都会为其运行用户功能。

问题

我不知道如何将用户连接变量传递给其他函数。我将conn net放在函数的参数中,但这只是一个占位符,因为我不确定这样做的正确方法。

此外,我的go func()在实现通道之后调用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
    }
}

1 个答案:

答案 0 :(得分:1)

在这里理解区别非常重要:这是并发性,而不是多线程,而这些是 goroutines ,而不是线程。这些概念是不可互换的。关于您的核心问题,您的实施存在一些重大问题:

  • 您正在启动goroutine 关闭变量,这些变量在循环迭代中共享,关键是conn。每次接受连接时,您将覆盖每个goroutine共享的conn。您应该将conn 传递到您的goroutine,使其具有自己的本地副本,或者在每次循环迭代中创建一个新的conn变量,而不是重复使用。 / li>
  • 您将在每个循环迭代中启动一个新的侦听器,由于旧的侦听器仍在使用该端口,因此它将失败。您不需要新的侦听器。只需继续在现有侦听器上调用ln.Accept即可继续接受新连接。查看net package文档介绍,或查看在Go中使用侦听器的任何代码
  • 您要在goroutine内创建newClient,然后尝试在goroutine之外引用它。甚至不会编译,而且不清楚您最初打算如何使用此通道。

netnet/http库中或GitHub上的一些流行项目中,查看一些现有的网络代码,以查看有关如何编写网络应用程序的良好示例。对博客文章或教程或操作方法进行一些网络搜索,结果很多。并且一定要阅读所用软件包的文档,这对您有很大帮助。