reiver / go-telnet

Package telnet provides TELNET and TELNETS client and server implementations, for the Go programming language, in a style similar to the "net/http" library that is part of the Go standard library, including support for "middleware"; TELNETS is secure TELNET, with the TELNET protocol over a secured TLS (or SSL) connection.
https://godoc.org/github.com/reiver/go-telnet
MIT License
267 stars 83 forks source link

Client hangs for a minute at first. #20

Open smegeath opened 3 years ago

smegeath commented 3 years ago

My telnet client is connecting to a non-go-telnet server and uses the basic client code provided in the documentation example. Connecting to my server with a standard telnet client gets an instant reply, but for some reason, my go-telnet client hangs reading for exactly a minute, then is fully interactive. Is there some configuration I should be using or something extra I should be doing with the Conn to flush it?

9072997 commented 2 years ago

according to the documentation for io.Reader

If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.

This library does not follow that convention. It appears to block until it is able to fill the buffer.

This program demonstrates the issue ```go package main import ( "fmt" "io" "log" "net" "time" "github.com/reiver/go-telnet" ) // start a TCP server that // - prints "hello world" // - waits 60 seconds // - then hangs up func DemoServer() { listener, err := net.Listen("tcp", ":1111") if err != nil { panic(err) } defer listener.Close() for { conn, err := listener.Accept() if err != nil { panic(err) } conn.Write([]byte("hello world\n")) time.Sleep(10 * time.Second) conn.Close() } } // ConnectWithBufferSize connects to the server at the given address and // and prints the output of each call to Read() using the given buffer size. func ConnectWithBufferSize(bufferSize int) { telnetClient, err := telnet.DialTo("localhost:1111") if err != nil { panic(err) } defer telnetClient.Close() buff := make([]byte, bufferSize) for { n, err := telnetClient.Read(buff) log.Printf("EOF:%t> %#v\n", err == io.EOF, string(buff[:n])) if err == io.EOF { break } if err != nil { panic(err) } } } func main() { go DemoServer() fmt.Println("=== Buffer Size 7 ===") ConnectWithBufferSize(7) fmt.Println("=== Buffer Size 1 ===") ConnectWithBufferSize(1) } ```

Output:

=== Buffer Size 7 ===
2022/03/30 15:45:06 EOF:false> "hello w"
2022/03/30 15:45:16 EOF:true> "orld\n"
=== Buffer Size 1 ===
2022/03/30 15:45:16 EOF:false> "h"
2022/03/30 15:45:16 EOF:false> "e"
2022/03/30 15:45:16 EOF:false> "l"
2022/03/30 15:45:16 EOF:false> "l"
2022/03/30 15:45:16 EOF:false> "o"
2022/03/30 15:45:16 EOF:false> " "
2022/03/30 15:45:16 EOF:false> "w"
2022/03/30 15:45:16 EOF:false> "o"
2022/03/30 15:45:16 EOF:false> "r"
2022/03/30 15:45:16 EOF:false> "l"
2022/03/30 15:45:16 EOF:false> "d"
2022/03/30 15:45:16 EOF:false> "\n"
2022/03/30 15:45:26 EOF:true> ""

Note that with a buffer size of 7 you immediately get hello w then you have to wait the full 10 seconds to get orld\n. A quick test with a debugger shows that it is hanging here

As a work around, you can use a buffer size of 1

I am not able to re-produce the behavior OP describes where the connection ever becomes interactive.

I have confirmed that this is fixed by either of PR #22 or PR #9.