Создать сервер и подключиться к нему - PullRequest
0 голосов
/ 22 сентября 2018

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

паника: ошибка времени выполнения: неверный адрес памяти или разыменование нулевого указателя [сигнал SIGSEGV: код нарушения сегментации = 0x1 addr = 0x18 pc = 0x496757]

Вот мой код для сервера

func RunServer(port string) {

    fmt.Println("Launching server...")
    ln, err := net.Listen("tcp", port)
    conn, _ := ln.Accept()

    // run loop forever (or until ctrl-c)
    for {

        // will listen for message to process ending in newline (\n)
        message, _ := bufio.NewReader(conn).ReadString('\n')

        // output message received
        fmt.Print("Message Received:", string(message))

        // sample process for string received
        newmessage := strings.ToUpper(message)

        // send new string back to client
        conn.Write([]byte(newmessage + "\n"))
    }
}

А вот код для клиента.

func createInitalClient(port int) {

    // run server then create a client that connects to it
    portToRunOn := fmt.Sprintf("%s%d", ":", port)
    go RunServer(portToRunOn)
}

func main() {

    createInitalClient(5000)

    // connect to this socket
    conn, _ := net.Dial("tcp", "127.0.0.1:5000")

    for {
        // read in input from stdin

        reader := bufio.NewReader(os.Stdin)
        fmt.Print("Text to send: ")
        text, _ := reader.ReadString('\n')

        // send to socket
        fmt.Fprintf(conn, text+"\n")

        // listen for reply
        message, _ := bufio.NewReader(conn).ReadString('\n')
        fmt.Print("Message from server: " + message)
    }
}

Я правильно это делаю или естьдругой подход, чтобы делать то, что я пытаюсь сделать?Я немного стесняюсь использовать goroutines, потому что введение асинхронного поведения может быть неправильно в моем случае.

EDIT 1 : похоже, эта ошибка происходит, потому что клиент пытается подключиться ксервер до его запуска.

РЕДАКТИРОВАТЬ 2 : Я (возможно) исправил это, добавив логический канал на сервере, который возвращает true прямо перед тем, как слушатели начнут принимать подключения.Тогда клиент подключается к серверу только в том случае, если значение, полученное из канала, равно true.Я не уверен, что это правильное исправление в этом сценарии, но, похоже, оно работает.

1 Ответ

0 голосов
/ 22 сентября 2018

Ваш сервер запущен в обычной программе, которая порождается асинхронно во время выполнения Go, и для ее планирования и выполнения потребуется некоторое время.В частности, среда выполнения не будет ожидать запуска серверной программы перед продолжением выполнения функции main.

Вам также необходимо:

  • организовать для серверной процедурыобщаться, когда сервер готов принимать соединения - использование канала является приемлемым механизмом для этого;или
  • повторное попытки подключения клиента до тех пор, пока подключение не будет принято - фактически выполняется опрос состояния готовности сервера.Например:

    // Predeclare "conn" to ensure it remains in scope outside the loop
    var conn net.Conn
    
    for {
        var err error
        conn, err = net.Dial("tcp", "127.0.0.1:5000")
    
        // Failed connection, try again in a second.
        // TODO: limit the number of attempts before giving up.
        if err != nil {
            time.Sleep(time.Second)
            continue
        }
    
        // Connected successfully. Continue.
        break
    }
    
    // do something with "conn"
    

Значения ошибок

Как отмечено в комментарии к вашему вопросу, ваш код игнорирует значения ошибок в нескольких местах.

Пожалуйста, не делайте этого в реальном производственном коде.Ошибки возвращаются по причине и могут указывать на проблему, внешнюю по отношению к вашему коду, которая мешает вашей программе должным образом продолжить выполнение.Вам необходимо проверить значения ошибок и принять соответствующие меры, если они возвращаются.Другие значения, возвращаемые при вызове функции, особенно что-либо из стандартной библиотеки, вряд ли будут иметь смысл, если возвращаемые error не nil.

Да, в итоге вы пишете if err != nil много.Это ожидаемо, и в некоторых случаях вы можете использовать различные шаблоны, чтобы избежать чрезмерного повторения кода.

...