Golang中的多线程套接字连接

Background

I'm creating a chatroom server using Golang. Every time a client connects to the server, I'm starting the Client function as a new thread, so that each client gets a thread that is listened to. I was able to create a simple client server connection based on this tutorial, but now I am trying to create connections for multiple clients so that they can send messages to chatrooms.

Code explanation

By following this tutorial, it looks like I can create a thread by using go func() and wait for a connection to be made by including a channel (<-newClient). I pass a bool value into the channel before calling the user function, because the user function will run forever and I want to make other client connections. Each client connection will have the user function running for it.

Problem

I don't know how to pass the user connection variable to my other functions. I'm placing conn net in the arguments for my functions, but this is just a placeholder because I'm not sure the proper way to do it.

Also, my go func() with the call to user() after the channel implementation is my best attempt at multithreading, but I'm not sure that I'm thinking about it right.


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('
')    // will listen for message to process ending in newline (
)
        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
    }
}

It is very important to understand a distinction here: this is concurrency, not multithreading, and these are goroutines, not threads. These concepts are not interchangeable. As to your core issue, there are some significant issues with your implementation:

  • You're starting a goroutine closing over variables that are shared across loop iterations, crucially conn. Every time you accept a connection, you overwrite the conn which is shared by every goroutine. You should instead pass the conn to your goroutine so it has its own local copy, or create a new conn variable in each loop iteration instead of re-using one.
  • You're starting a new listener in every loop iteration, which is going to fail because the old listener is still using that port. You don't need a new listener. Just keep calling ln.Accept on the existing listener to continue accepting new connections. Take a look at the introduction of the documentation for the net package, or check any code that uses listeners in Go for an example.
  • You're creating newClient inside the goroutine, then trying to reference it outside the goroutine. This won't even compile, and it's unclear what you are trying to do with this channel in the first place.

Take a look at some existing networking code - in the net or net/http libraries or some popular projects on GitHub - to see good examples of how to write a network application. Do some web searches for blog posts or tutorials or how-to's, there are tons out there. And definitely read the documentation for the packages you're using, it will help you a lot.