Многопоточные сокетные соединения в Голанге - PullRequest
0 голосов
/ 31 декабря 2018

Фон

Я создаю сервер чата с помощью Golang.Каждый раз, когда клиент подключается к серверу, я запускаю функцию Client как новый поток, так что каждый клиент получает поток, который прослушивается.Мне удалось создать простое соединение клиент-сервер на основе этого учебника , но сейчас я пытаюсь создать соединения для нескольких клиентов, чтобы они могли отправлять сообщения в чаты.

Объяснение кода

Следуя этого урока , похоже, что я могу создать поток с помощью go func() и ждать установления соединения, включая канал (<-newClient).Я передаю значение bool в канал перед вызовом пользовательской функции, потому что пользовательская функция будет работать вечно, и я хочу установить другие клиентские подключения.Для каждого клиентского соединения будет работать пользовательская функция.

Проблема

Я не знаю, как передать переменную пользовательского соединения другим моим функциям.Я помещаю conn net в аргументы для своих функций, но это просто заполнитель, потому что я не уверен, как это сделать.

Кроме того, мой go func() с вызовом пользователя() после реализации канала моя лучшая попытка многопоточности, но я не уверен, что думаю об этом правильно.


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 голосов
/ 31 декабря 2018

Здесь очень важно понять различие: это параллелизм , а не многопоточность, и это подпрограммы , а не потоки.Эти понятия не являются взаимозаменяемыми.Что касается вашей основной проблемы, у вашей реализации есть несколько существенных проблем:

  • Вы запускаете программу , закрывающуюся над переменными, которые совместно используются итерациями цикла, крайне важно conn,Каждый раз, когда вы принимаете соединение, вы перезаписываете conn, который используется всеми программами.Вместо этого вы должны передать conn вашей программе, чтобы она имела свою собственную локальную копию, или создать новую переменную conn в каждой итерации цикла вместо ее повторного использования.
  • Вы запускаете нового прослушивателя в каждой итерации цикла, что приведет к сбою, поскольку старый прослушиватель все еще использует этот порт.Вам не нужен новый слушатель.Просто продолжайте вызывать ln.Accept на существующем приемнике, чтобы продолжить принимать новые подключения.Взгляните на введение документации для net пакета или отметьте любой код, который использует слушатели в Go для примера.
  • Вы создаете newClient внутри goroutine, затем пытаетесь сослаться на него вне goroutine.Это даже не скомпилируется, и неясно, что вы пытаетесь сделать с этим каналом.

Взгляните на некоторый существующий сетевой код - в net или net/http библиотеки или некоторые популярные проекты на GitHub - чтобы увидеть хорошие примеры того, как написать сетевое приложение.Сделайте некоторые веб-поиски для сообщений в блоге или учебные пособия или практические рекомендации, есть тонны там.И обязательно прочитайте документацию по пакетам, которые вы используете, это вам очень поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...