Сбой TCP-сервера после первого ответа - PullRequest
0 голосов
/ 29 июня 2018

Примечание

Я переписал этот вопрос для награды, так как мне удалось выяснить, как решить первый вопрос, но я не хотел начинать новый вопрос. Приведенные ниже комментарии относятся к первоначальному вопросу, а не к пересмотренному.

Описание выпуска

Мой tcp-клиент успешно выполняет запрос tcp-сервера один раз, возвращает ответ, а затем последующие запросы к серверу от клиента не выполняются. Кроме того, если я завершаю работу клиента и перезагружаю его, это также не удается с первой попытки.

Вот как выглядит моя командная строка:

root@ubuntuT:/home/jon/gocode/udps#  ./udpservtcpclient 
Text to send: SampleQuery
Message from server: SampleResponse
Text to send: SampleQuery
((End - No Response))
root@ubuntuT:/home/jon/gocode/udps# ./udpservtcpclient 
Text to send: SampleQuery
((End - No Response))

Что я ожидаю

Я ожидаю, что смогу бесконечно запрашивать tcp-сервер у tcp-клиента, и каждый раз tcp-сервер будет возвращать ответ от UDP-сервера. Кроме того, если я завершаю работу tcp-клиента и перезагружаю его, он также должен правильно запросить tcp-сервер без сбоев.

Что я думаю

Что-то не так с сервером TCP, принимающим соединения. Я переместил UDP-часть в отдельном коде (не здесь, так как не важно, он все еще не работает) в его собственную функцию, которая открывает и закрывает соединения UDP, и она все еще не работает после первого соединения.

UPDATE

Я обновил код для отображения «Accepted Connection» чуть ниже c,err:=serverConn.Accept(), и он печатался только один раз для первого запроса. любые последующие запросы от клиента не отображали строку, так что это связано с принятием соединений

Sourcecode

Код сервера:

package main

import (
  "log"
  //"fmt"
  "net"
  //"strings"
  "bufio"
  //"time"
  //"github.com/davecgh/go-spew/spew"
)

var connUDP *net.UDPConn

func udpRoutine(query string)(string){
  connUDP.Write([]byte(query))
  buf:= make([]byte,128)
  n,err:=connUDP.Read(buf[0:])
  if err != nil{
    log.Fatal(err)
  }
  response := string(buf[0:n])
  return response
}

func handle(conn net.Conn) error {
  defer func(){
    conn.Close()
  }()
  r := bufio.NewReader(conn)
  w := bufio.NewWriter(conn)
  scanr := bufio.NewScanner(r)
  for {
    scanned := scanr.Scan()
    if !scanned {
      if err := scanr.Err(); err != nil {
    log.Printf("%v(%v)", err, conn.RemoteAddr())
    return err
      }
      break
    }
    response:=udpRoutine(scanr.Text())
    w.WriteString(response+"\n")
    w.Flush()
  }
  return nil
}

func main(){

   // setup tcp listener
   serverConn,err := net.Listen("tcp","127.0.0.1:8085")
   if err != nil{
    log.Fatal(err)
   }
   defer serverConn.Close()

   // setup udp client
   udpAddr,err:=net.ResolveUDPAddr("udp4","127.0.0.1:1175")
   if err != nil{
    log.Fatal(err)
   }
   connUDP,err=net.DialUDP("udp",nil,udpAddr)
   if err != nil{
    log.Fatal(err)
   }
   defer connUDP.Close()

   for{
      c,err:=serverConn.Accept()
      if err != nil{
    log.Fatal(err)
      }
      //c.SetDeadline(time.Now().Add(5))
      go handle(c)
    }
  }

Код клиента:

package main

import "net"
import "fmt"
import "bufio"
import "os"

func main() {

  // connect to this socket
  conn, _ := net.Dial("tcp", "127.0.0.1:8085")
  for { 
    reader := bufio.NewReader(os.Stdin)
    // read in input from 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)
  }
}

1 Ответ

0 голосов
/ 03 июля 2018

Кажется, здесь есть две проблемы:

1) UDP-сервер

Ваш вопрос описывает проблему, когда клиент не может сделать второй запрос к серверу.

Я использовал простой эхо-сервер UDP, а также код, который вы разместили для сервера и клиента, и не могу воспроизвести проблему (я все еще могу сделать несколько запросов к серверу), поэтому я подозреваю, что это связано с Используемый вами UDP-сервер (код, который я не вижу в этом вопросе).

Я предлагаю вам попробовать это на простом UDP-сервере, который просто выводит сообщения обратно:

package main

import (
    "fmt"
    "net"
)

func main() {
    conn, _ := net.ListenUDP("udp", &net.UDPAddr{IP:[]byte{0,0,0,0},Port:1175,Zone:""})
    defer conn.Close()
    buf := make([]byte, 1024)
    for {
        n, addr, _ := conn.ReadFromUDP(buf)
        conn.WriteTo(buf[0:n], addr)
        fmt.Println("Received ", string(buf[0:n]), " from ", addr)
    }
}

2) Дополнительная новая строка в TCP-клиенте

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

Кажется, это вызвано второй проблемой, которая является этой строкой в ​​клиенте:

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

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

Но в клиенте вы читаете только одну строку, поэтому вторая строка кажется ожидающей, пока клиент не подключится снова.

Это можно исправить, просто изменив это на:

// send to socket
fmt.Fprintf(conn, text)

Выход для фиксированного кода

Используя этот UDP-сервер и внося эти изменения в клиент, я получаю вывод при запуске всех трех компонентов:

Text to send: first msg
Message from server: first msg
Text to send: second msg
Message from server: second msg
Text to send: third msg
Message from server: third msg
Text to send: 

Затем я могу остановить только клиент, запустить его снова, и он продолжит работать:

Text to send: fourth msg
Message from server: fourth msg
Text to send: 

Дополнительные примечания

О двух других строках в коде клиента, которые используют переводы строки:

// read in input from stdin
fmt.Print("Text to send: ")
text,_ := reader.ReadString('\n')

Эта новая строка нужна там, потому что когда вы вводите текст с помощью стандартного ввода, вы заканчиваете строку, используя клавишу ввода (и, таким образом, заканчиваете строку новой строкой), поэтому строка должна читаться до символа \n .

message, _ := bufio.NewReader(conn).ReadString('\n')

Эта причина необходима, когда сервер записывает ответ на соединение, которое он делает w.WriteString(response+"\n"). Таким образом, ответ включает в себя новую строку в конце, и вы должны прочитать эту строку при чтении текста ответа.

...