locked
Where to put receiving data code in C# Winform Telnet RRS feed

  • Question

  • I use this Telnet Library:

    TelnetConnection.cs file

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net.Sockets;
    
    namespace USSR
    {
        enum Verbs
        {
            WILL = 251,
            WONT = 252,
            DO = 253,
            DONT = 254,
            IAC = 255
        }
    
        enum Options
        {
            SGA = 3
        }
    
        class TelnetConnection
        {
            TcpClient tcpSocket;
    
            int TimeOutMs = 100;
    
            public TelnetConnection(string Hostname, int Port)
            {
                tcpSocket = new TcpClient(Hostname, Port);
    
            }
    
            public string Login(string Username, string Password, int LoginTimeOutMs)
            {
                int oldTimeOutMs = TimeOutMs;
                TimeOutMs = LoginTimeOutMs;
                string s = Read();
                if (!s.TrimEnd().EndsWith(":"))
                    throw new Exception("Failed to connect : no login prompt");
                WriteLine(Username);
    
                s += Read();
                if (!s.TrimEnd().EndsWith(":"))
                    throw new Exception("Failed to connect : no password prompt");
                WriteLine(Password);
    
                s += Read();
                TimeOutMs = oldTimeOutMs;
                return s;
            }
    
            public void WriteLine(string cmd)
            {
                Write(cmd + "\n");
            }
    
            public void Write(string cmd)
            {
                if (!tcpSocket.Connected) return;
                byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF", "\0xFF\0xFF"));
                tcpSocket.GetStream().Write(buf, 0, buf.Length);
            }
    
            public string Read()
            {
                if (!tcpSocket.Connected) return null;
                StringBuilder sb = new StringBuilder();
                do
                {
                    ParseTelnet(sb);
                    System.Threading.Thread.Sleep(TimeOutMs);
                } while (tcpSocket.Available > 0);
                return sb.ToString();
            }
    
            public bool IsConnected
            {
                get { return tcpSocket.Connected; }
            }
    
            void ParseTelnet(StringBuilder sb)
            {
                while (tcpSocket.Available > 0)
                {
                    int input = tcpSocket.GetStream().ReadByte();
                    switch (input)
                    {
                        case -1:
                            break;
                        case (int)Verbs.IAC:
                            // interpret as command
                            int inputverb = tcpSocket.GetStream().ReadByte();
                            if (inputverb == -1) break;
                            switch (inputverb)
                            {
                                case (int)Verbs.IAC:
                                    //literal IAC = 255 escaped, so append char 255 to string
                                    sb.Append(inputverb);
                                    break;
                                case (int)Verbs.DO:
                                case (int)Verbs.DONT:
                                case (int)Verbs.WILL:
                                case (int)Verbs.WONT:
                                    // reply to all commands with "WONT", unless it is SGA (suppres go ahead)
                                    int inputoption = tcpSocket.GetStream().ReadByte();
                                    if (inputoption == -1) break;
                                    tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
                                    if (inputoption == (int)Options.SGA)
                                        tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO);
                                    else
                                        tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
                                    tcpSocket.GetStream().WriteByte((byte)inputoption);
                                    break;
                                default:
                                    break;
                            }
                            break;
                        default:
                            sb.Append((char)input);
                            break;
                    }
                }
            }
        }
    }
    

    and here's how to use this:


    //create a new telnet connection to hostname "gobelijn" on port "23"
    TelnetConnection tc = new TelnetConnection("gobelijn", 23);
    
    //login with user "root",password "rootpassword", using a timeout of 100ms, 
    //and show server output
    string s = tc.Login("root", "rootpassword",100);
    Console.Write(s);
    
    // server output should end with "$" or ">", otherwise the connection failed
    string prompt = s.TrimEnd();
    prompt = s.Substring(prompt.Length -1,1);
    if (prompt != "$" && prompt != ">" )
        throw new Exception("Connection failed");
    
    prompt = "";
    
    // while connected
    while (tc.IsConnected && prompt.Trim() != "exit" )
    {
        // display server output
        Console.Write(tc.Read());
    
        // send client input to server
        prompt = Console.ReadLine();
        tc.WriteLine(prompt);
    
        // display server output
        Console.Write(tc.Read());
    }
    
    Console.WriteLine("***DISCONNECTED");
    Console.ReadLine();
    
    




    I converted this c# console program into C# Winform program. I am able to send data to my device (microcontroller, to be specific) and I'm actually done in this part. The problem is that how am I suppose to read the device/server's response?

    If you're gonna open the link and read some part of the code how to use the library, it shows here how to send data to the server and read a data from the server.


    // while connected
    while (tc.IsConnected && prompt.Trim() != "exit" )
    {
    // display server output
    Console.Write(tc.Read());
    
    // send client input to server
    prompt = Console.ReadLine();
    tc.WriteLine(prompt);
    
    // display server output
    Console.Write(tc.Read());
    }


    I use WriteLine in sending data to the device, as I've said, I'm done with this. I just don't know where to put the tc.Read(); part in my winform program.

    The device is send this long string with a length of 89 continuously and quite fast!

    sensor1: 0.10meters sensor2: 1.51meters sensor3: 2.03meters sensor4: 1.7meters temp: 21degC

    By the way, I will put each values to the specific labels. So here's my code in getting the values using substring:


      private void timer2_Tick(object sender, EventArgs e)
        {
            //"Sensor1: 0.00meters Sensor2: 0.00meters Sensor3: 0.00meters Sensor4: 0.00meters 21.00degC"
            if (connectedChecker1 == true)
            {
                dataReceived = tc.Read();
                if (dataReceived.Length == 89)
                {
                    tempVal.Text = (str1.Substring(80, 5)) + "°C";
                    frontVal.Text = str1.Substring(9, 10);
                    leftVal.Text = str1.Substring(29, 10);
                    backVal.Text = str1.Substring(49, 10);
                    rightVal.Text = str1.Substring(69, 10);
                    dataReceived = "";
                }
            }
        }

    Here's my whole winform code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Net.Sockets;
    
    namespace USSR
    {
        public partial class mainForm : Form
        {
            TelnetConnection tc;
            public bool keyPressChecker = false;
            public bool connectedChecker = false;
    
            TelnetConnection unoTc;
            public bool keyPressChecker1 = false;
            public bool connectedChecker1 = false;
    
            public string camIP = "192.168.0.30";
            public string ethernetIP = "192.168.0.105";
            public string servoUnoIp = "192.168.0.100";
            public int seconds = 0;
            public string promptValue;
    
            public string str1 = "Sensor1: 0.00meters Sensor2: 0.00meters Sensor3: 0.00meters Sensor4: 0.00meters 21.00degC";
            public string dataReceived = "";
            public mainForm()
            {
                InitializeComponent();
    
                this.unoTc = null;
                this.connectedChecker = false;
                timer1.Start();
                timer2.Enabled = true;
                timer2.Start();
                //MessageBox.Show(str1.Length.ToString()); 89 output
    
    
            }
    
            private void radioButton2_CheckedChanged(object sender, EventArgs e)
            {
                try
                {
                    if (submarineRadioBtn.Checked)
                        System.Diagnostics.Process.Start("dummySub.exe");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
    
            private void centerBtnCamera_Click(object sender, EventArgs e)
            {
    
                if (connectedChecker)
                    unoTc.WriteLine("L");
    
            }
    
            private void forwardBtn_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    this.unoTc.WriteLine("W");
            }
    
            private void connectToolStripMenuItem1_Click(object sender, EventArgs e)
            {
    
            }
    
            private void controlKeyDownCheckBox_CheckedChanged(object sender, EventArgs e)
            {
                if (controlKeyDownCheckBox.Checked == true)
                {
                    keyPressChecker = true;
                }
                else
                {
                    keyPressChecker = false;
                }
            }
    
            private void controlKeyDownCheckBox_KeyDown(object sender, KeyEventArgs e)
            {
                // if Check box is ticked!
                if (keyPressChecker == true)
                {
                    // if W - increase speed
                    if (e.KeyCode == Keys.W)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("W");
                    }
                    // if S - decrease speed
                    if (e.KeyCode == Keys.S)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("S");
                    }
                    // if A - turnleft raddle
                    if (e.KeyCode == Keys.A)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("A");
                    }
                    // if D - turnright radle
                    if (e.KeyCode == Keys.D)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("D");
                    }
                    // if J - turnleft cam
                    if (e.KeyCode == Keys.J)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("J");
                    }
                    // if K - turnright cam
                    if (e.KeyCode == Keys.K)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("K");
                    }
                    // if L - turn cam CENTER
                    if (e.KeyCode == Keys.L)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("L");
                    }
    
                }
            }
    
            private void reverseBtn_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    unoTc.WriteLine("S");
            }
    
            private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
            {
    
            }
    
            // The following catches when user stops pressing W or S
            private void controlKeyDownCheckBox_KeyUp(object sender, KeyEventArgs e)
            {
                if (keyPressChecker == true)
                {
                    if (e.KeyCode == Keys.W)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("O"); //decrease to MID PT.
                    }
                    if (e.KeyCode == Keys.S)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("P"); //decrease speed to MID PT.
                    }
    
    
                    if (e.KeyCode == Keys.A)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("I"); //return raddle to center
                    }
                    if (e.KeyCode == Keys.D)
                    {
                        if (connectedChecker)
                            unoTc.WriteLine("I"); //return raddle to center
                    }
    
                }
            }
    
            private void exitToolStripMenuItem_Click(object sender, EventArgs e)
            {
                Application.Exit();
            }
    
            private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
            {
                MessageBox.Show("A Project Design by: " + "\n" + "J.Chua" + "\n" +
                    "W.Biol" + "\n" + "J.Puno" + "\n" + "M.Hufana");
            }
    
            private void leftBtn_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    unoTc.WriteLine("A");
            }
    
            private void rightBtn_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    unoTc.WriteLine("D");
            }
    
            private void vesselBoardToolStripMenuItem_Click(object sender, EventArgs e)
            {
                //MessageBox.Show(ethernetIP.ToString());
                //MessageBox.Show(servoUnoIp.ToString());
                try
                {
                    //create a new telnet connection for MEGA
                   tc = new TelnetConnection(ethernetIP, 23);
                    if (tc.IsConnected)
                      connectedChecker1 = true;
    
                    //create a new telnet connection for Uno
                   unoTc = new TelnetConnection(servoUnoIp, 23);
                   if (unoTc.IsConnected)
                     connectedChecker = true;
    
                   statusLbl.Text = "Connected";
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Check the ip address of the boards");
                }
            }
    
            private void vesselBoardToolStripMenuItem1_Click(object sender, EventArgs e)
            {
    
            }
    
            private void iPCameraToolStripMenuItem_Click(object sender, EventArgs e)
            {
    
                try
                {
                    string newIPOfCam = "http://admin:admin@";
                    webBrowser1.Navigate(newIPOfCam + camIP);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
    
            private void disconnectToolStripMenuItem_Click_1(object sender, EventArgs e)
            {
                try
                {
                    unoTc = null;
                    tc = null;
                    connectedChecker = false;
                    connectedChecker1 = false;
    
                    statusLbl.Text = "Disconnected";
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
    
            private void leftBtnCamera_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    unoTc.WriteLine("J");
            }
    
            private void rightBtnCamera_Click(object sender, EventArgs e)
            {
                if (connectedChecker)
                    unoTc.WriteLine("K");
            }
    
            public static string ShowDialog(string text, string caption)
            {
                Form prompt = new Form();
                prompt.Width = 280;
                prompt.Height = 150;
                prompt.FormBorderStyle = FormBorderStyle.FixedDialog;
                prompt.Text = caption;
                prompt.StartPosition = FormStartPosition.CenterScreen;
                Label textLabel = new Label() { Left = 50, Top = 20, Text = text };
                TextBox textBox = new TextBox() { Left = 50, Top = 50, Width = 150 };
                Button confirmation = new Button() { Text = "Ok", Left = 100, Width = 100, Top = 70 };
                confirmation.Click += (sender, e) => { prompt.Close(); };
                prompt.Controls.Add(textBox);
                prompt.Controls.Add(confirmation);
                prompt.Controls.Add(textLabel);
                prompt.AcceptButton = confirmation;
                prompt.ShowDialog();
                return textBox.Text;
            }
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                seconds += 1;
                if (seconds == 1)
                {
                    timer1.Enabled = false;
                    timer1.Stop();
                    while (promptValue != "ussr2015")
                        promptValue = mainForm.ShowDialog("Enter password:",
                        "Oops...");
                }
            }
    
            private void iPCamHostNameIPToolStripMenuItem_Click(object sender, EventArgs e)
            {
                camIP = mainForm.ShowDialog("Enter IP/HostName",
                         "IP CAMERA");
            }
    
            private void megaBoardsIPToolStripMenuItem_Click(object sender, EventArgs e)
            {
                ethernetIP = mainForm.ShowDialog("Enter IP/HostName",
                        "UNO-sensor Board");
            }
    
            private void unoBoardsIPToolStripMenuItem_Click(object sender, EventArgs e)
            {
                servoUnoIp = mainForm.ShowDialog("Enter IP/HostName",
                        "UNO BOARD");
            }
    
            private void manualToolStripMenuItem_Click(object sender, EventArgs e)
            {
                manualForm frm2 = new manualForm();
                frm2.ShowDialog();
            }
    
            private void timer2_Tick(object sender, EventArgs e)
            {
                //"Sensor1: 0.00meters Sensor2: 0.00meters Sensor3: 0.00meters Sensor4: 0.00meters 21.00degC"
                if (connectedChecker1 == true)
                {
                    dataReceived = tc.Read();
                    if (dataReceived.Length == 89)
                    {
                        tempVal.Text = (str1.Substring(80, 5)) + "°C";
                        frontVal.Text = str1.Substring(9, 10);
                        leftVal.Text = str1.Substring(29, 10);
                        backVal.Text = str1.Substring(49, 10);
                        rightVal.Text = str1.Substring(69, 10);
                        dataReceived = "";
                    }
                }
            }
    
        }
    }
    




    Wednesday, February 11, 2015 6:26 PM

Answers

  • Although it's a bigger change, my opinion is that you should use non-blocking IO for your socket (a.k.a. asynchronous reads).  A windows forms application is an event-driven program, and you should be using asynchronous socket operations.

    So after your connection is completed you should call BeginReceive on your socket, and pass in a callback -- let's call it OnReceiveCompleted.

    Then when your callback is called, in OnReceiveCompleted, you can parse the bytes that have been read and begin a new receive operation by calling BeginReceive again on your socket.

    When your parser locates some kind of a construct in your protocol that needs processing back in the UI, it can Invoke a call on the UI thread to update things.

    You can also make use of an event pattern in your TelnetConnection class to allow for the parser to tell someone that something needs to be done, and the consumer of the TelnetConnection can provide their own delegate that processes server messages.

    Does this give you enough to go on or do you need examples?  If you need to see an example, please start by looking at my answer in this thread about asynchronous sockets.

    • Marked as answer by Gvcp13 Thursday, February 12, 2015 2:51 AM
    Wednesday, February 11, 2015 7:37 PM

All replies

  • Although it's a bigger change, my opinion is that you should use non-blocking IO for your socket (a.k.a. asynchronous reads).  A windows forms application is an event-driven program, and you should be using asynchronous socket operations.

    So after your connection is completed you should call BeginReceive on your socket, and pass in a callback -- let's call it OnReceiveCompleted.

    Then when your callback is called, in OnReceiveCompleted, you can parse the bytes that have been read and begin a new receive operation by calling BeginReceive again on your socket.

    When your parser locates some kind of a construct in your protocol that needs processing back in the UI, it can Invoke a call on the UI thread to update things.

    You can also make use of an event pattern in your TelnetConnection class to allow for the parser to tell someone that something needs to be done, and the consumer of the TelnetConnection can provide their own delegate that processes server messages.

    Does this give you enough to go on or do you need examples?  If you need to see an example, please start by looking at my answer in this thread about asynchronous sockets.

    • Marked as answer by Gvcp13 Thursday, February 12, 2015 2:51 AM
    Wednesday, February 11, 2015 7:37 PM
  • hello sir Wyck, I saw your answers on the page you gave. I'll try my best to understand and to implement the examples.

    I will mark your reply as an answer if I'm done. :) I'll post here my follow up question. thank you so much!

    More replies are welcome :)

    Thursday, February 12, 2015 2:24 AM
  • ok, so I marked you answer as an answer sir.

    So the minimalistic telnet library that I'm using doesn't use asynchronous reads? right?

    Good thing that the deadline of my project was moved! phew! Thank you so much for your answer. I'll just post another question if ever I have one in the future. I'll modify the program, BUT...... I think I will retain the telnet library for SENDING data. I'll just add a receiving function in my program. thanks. Reply if you have more suggestion. Thank you so much again.

    Thursday, February 12, 2015 2:55 AM