2016-05-23 2 views
-2

Я пытаюсь реализовать с помощью SetDeadline() неблокирующая Accept() и лучшее, что я пришел до сих пор является следующий фрагмент кода (это рабочая программа v1.6.2 Go):Настройка тайм-аут для TCP слушателя

package main 

import (
    "net" 
    "log" 
    "time" 
) 

func createClient() { 
    tcpConn, err := net.DialTCP("tcp4", nil, &net.TCPAddr{ 
     IP:  net.IPv4(127, 0, 0, 1), 
     Port: 12819, 
    }) 
    if err != nil { 
     log.Fatalln("Error connecting to the server!") 
    } 
    log.Println("Managed to dial!") 
    tcpConn.Close() 
} 

func main() { 
    go createClient() 
    l, err := net.ListenTCP("tcp4", &net.TCPAddr{ 
     IP:  net.IPv4(127, 0, 0, 1), 
     Port: 12819, 
    }) 
    if err != nil { 
     log.Fatalln("Can't listen on provided IP/port!") 
    } 
    defer l.Close() 
    if err = l.SetDeadline(time.Now().Add(time.Nanosecond)); err != nil { 
     log.Fatalln("Can't set appropriate deadline!") 
    } 
    tcpConn, err := l.AcceptTCP() 
    if err != nil { 
     if opError, ok := err.(*net.OpError); ok && opError.Timeout() { 
      log.Fatalln("Timeout error!") 
     } 
     log.Fatalln("Error while accepting connection!") 
    } 
    log.Println("Accepted new connection!") 
    tcpConn.Close() 
} 

Проблема в том, что я всегда получаю Timeout error!. Насколько я понимаю, это потому, что по вызову получателя времени AcceptTCP() будет указан ранее установленный крайний срок. Попробуйте изменить его на time.Microsecond, и вы, вероятно, получите тот же результат (если у вас нет процессора медленнее, чем у меня). Вещи начинают меняться только тогда, когда крайний срок получает не менее time.Second. Вот когда я начинаю получать Accepted new connection!/Managed to dial!.

Поэтому я думаю, что я прибил проблему. Есть предположения?

+0

Если вы хотите использовать 'select' use' syscall.Select', но это почти всегда неправильный способ сделать это в Go – JimB

ответ

2

Принятие должно быть блокирующим. Вы не хотите устанавливать крайний срок для прослушивания/принятия, так как вы хотите, чтобы он постоянно прослушивал новые подключения.

Вам необходимо поместить accept внутри цикла и в основном запустить новую процедуру go для обработки соединения и возврата к ожиданию подключения нового клиента (Accept).

Вот типичный сервер в Go:

package main 

import (
    "fmt" 
    "log" 
    "net" 
    "os" 
) 

func main() { 
    l, err := net.Listen("tcp", "localhost:12819") 
    if err != nil { 
     log.Fatalln("Can't listen on provided IP/port!") 
    } 
    defer l.Close() 

    for { 
     // Listen for an incoming connection. 
     conn, err := l.Accept() 
     if err != nil { 
      fmt.Println("Error accepting: ", err.Error()) 
      os.Exit(1) 
     } 

     // Handle connections in a new goroutine. 
     go handleRequest(conn) 
    } 
} 

func handleRequest(conn net.Conn) { 
    buf := make([]byte, 1024) 
    if _, err := conn.Read(buf); err != nil { 
     fmt.Println("Error reading:", err.Error()) 
    } 
    conn.Write([]byte("Message received.")) 
    conn.Close() 
} 

Вы можете связаться с ним с помощью следующей команды из вашей оболочки:

telnet localhost 12819 

Тип команды и ваш запрос будет обработан и обработан ,

Как вы видите, команда accept предназначена для блокировки с целью. SetDeadline на сервере обычно используется далее на этапе обработки до таймаута при считывании данных, поступающих от клиента.

+0

Ваше второе утверждение противоречит простому существованию 'SetDeadline()' call on 'TCPListener типа. – mesmerizingr

+0

Нет. Тот факт, что setDeadline существует, не означает, что вам нужно использовать его в общем случае для создания сервера. Вы используете это неправильно. Я добавил пример с типичным базовым кодом сервера Go. –

+2

SetDeadline используется для запуска тайм-аута при чтении данных на сервере. Не задавайте вопросов, если вы не хотите слушать ответ :) –

Смежные вопросы