I have the simplest C# program that reads bytes from a NetworkStream and sends their textual representation back:
using System.Net;
using System.Net.Sockets;
using System.Text;
var listener = new TcpListener(IPAddress.Any, 5050);
listener.Start();
var client = listener.AcceptTcpClient();
var stream = client.GetStream();
int b;
while ((b = stream.ReadByte()) != -1) {
var str = $"{(byte)b:x2} ";
Console.Write(str);
stream.Write(Encoding.ASCII.GetBytes(str));
}
For example, if I telnet to localhost 5050
and write hello<enter>
, I get 68 65 6c 6c 6f 0d 0a
.
As soon as I press Ctrl-C in the telnet window, the program echoes ff f4 ff fd 06
in its console window, but nothing is received by the telnet client. Anything else I enter in the telnet client after that is also echoed in the program’s console but is never received by the telnet client. This happens with telnet from WSL2 Ubuntu or from MSYS2.
Native Windows telnet client keeps working fine (and actually sends the data character by character with Ctrl-C represented as 03
).
2
Answers
This behavior is likely due to the telnet client sending a "break" signal when you press Ctrl-C. The bytes you see echoed in the console window (ff f4 ff fd 06) are the telnet protocol commands that are sent to indicate the "break" signal. When you press Ctrl-C in the telnet window, the client sends the ASCII control character ETX (End of Text) which has a value of 0x03. This is different from the Ctrl-C keyboard combination in Windows, which generates the ASCII control character ETX and also sends a SIGINT signal to the running process.
Try adding this to your while loop:
What you’re seeing is the interaction of the (linux) terminal with the telnet client and protocol
When you hit ctrlC in a linux (including WSL) terminal window1, it sends a SIGINT to the forground process running in that terminal. If that process is a telnet client, it will catch that signal and send a TELNET INTERRUPT-PROCESS command (
ff f4
) to whatever "service" it is talking to (in this case your simple C# program)When you hit ctrlC in a native windows terminal, it just sends a
03
ascii character (ETX).So to deal with this, you can extend your simple program to understand (some) TELNET protocol commands. There’s a summary of how the protocol works on wikipedia, but it basically just comes down to recognizing 0xff bytes in the input and then doing something based on the following byte or bytes.
1This is the "normal" behavior, though it does depend on the terminal mode. If the terminal is put into "raw" mode all the special character processing and signalling will be disabled and ctrlC will just send ascii code 3 (ETX)