Ошибки при подключении многих клиентов к серверу Go

#sockets #go #goroutine

#сокеты #Вперед #goroutine

Вопрос:

полный код можно загрузить по адресу https://groups.google.com/forum /#!topic/golang-nuts/e1Ir__Dq_gE

Может ли кто-нибудь помочь мне улучшить этот пример кода до нулевой ошибки? Я думаю, это поможет нам разработать клиент / серверный код без ошибок.

мои шаги по разработке:

  1. Создайте сервер, который мог бы обрабатывать несколько подключений с помощью goroutine.
  2. Создайте клиент, который отлично работает с простым протоколом.
  3. Разверните клиент для имитации нескольких клиентов (с параметром -n = 1000 клиентов по умолчанию)
  4. ЗАДАЧА: попытаться уменьшить блокировку сервера
  5. ЗАДАЧА: попробуйте использовать bufioдля увеличения пропускной способности

Я обнаружил, что этот код очень нестабилен и содержит три проблемы:

  1. запустите 1000 клиентов, у одного из них возникает ошибка EOF при чтении с сервера.
  2. запускаю 1050 клиентов, слишком много открытых файлов в ближайшее время (ни один клиент не открылся).
  3. запуск 1020 клиентов, ошибка во время выполнения с длинными стеками трассировки.

     Start pollServer: pipe: too many open files
    panic: runtime error: invalid memory address or nil pointer dereference
    
    [signal 0xb code=0x1 addr=0x28 pc=0x4650d0]
      

Здесь я вставляю свой более упрощенный код.

 const ClientCount = 1000
func main() {
    srvAddr := "127.0.0.1:10000"
    var wg sync.WaitGroup
    wg.Add(ClientCount)
    for i := 0; i < ClientCount; i   {
        go func(i int) {
            client(i, srvAddr)
            wg.Done()
        }(i)
    }
    wg.Wait()
}
func client(i int, srvAddr string) {
    conn, e := net.Dial("tcp", srvAddr)
    if e != nil {
        log.Fatalln("Err:Dial():", e)
    }
    defer conn.Close()
    conn.SetTimeout(proto.LINK_TIMEOUT_NS)
    defer func() {
        conn.Close()
    }()

    l1 := proto.L1{uint32(i), uint16(rand.Uint32() % 10000)}
    log.Println(conn.LocalAddr(), "WL1", l1)
    e = binary.Write(conn, binary.BigEndian, amp;l1)
    if e == os.EOF {
        return
    }
    if e != nil {
        return
    }
    // ...
}
  

Комментарии:

1. Этот сайт может быть полезен. В нем дается подробный обзор с примерами сетевого кода в Go: jan.newmarch.name/go

2. На какой операционной системе вы запускаете клиент / сервер?

3. Проблема № 2, вероятно, вызвана ограничением на 1024 файловых дескриптора в вашей операционной системе. Также вы откладываете соединение. Дважды закрыть (), что может быть проблемой.

4. @RCE, спасибо, я уверен, что проблема № 2 вызвана ulimit -n 1024. Я удалил соединение defer. Ошибка Close () дважды, но она не может получить никакой помощи в этой проблеме.

5. Каким будет протокол? Действительно ли необходимо, чтобы одновременно было открыто так много сокетов? У вас будут системные ресурсы, используемые для каждого из этих открытых сокетов.

Ответ №1:

Этот ответ на serverfault [1] предполагает, что для серверов, которые могут обрабатывать большое количество подключений, необходимо установить более высокий ulimit. Также проверьте приложения на утечки памяти или файловых дескрипторов с помощью lsof.

 ulimit -n 99999
  

[1] https://serverfault.com/a/48820/110909