none
UWP TCP Client RRS feed

  • Question

  • this may sound like a basic problem but I am trying to use a tcp connection.

    I want to create a connection to a remote device. I then need to wait for the log in credentials then send the user name and password. After authentication I can just send and receive data.  

    I used Streamsocket in other applications but since I will create a connection and keep it open the I don't think this works.

    I had tried the application in a forms app and by using a separate thread to start the listener it worked but threading is not permitted in UWP.

    Here is what I have.

     public sealed partial class MainPage : Page
        {
            TcpClient _client = new TcpClient();
            private NetworkStream in_stream;
            private Thread rx_thread = null;
            String _clientResponse = string.Empty;
            private bool connected;
    
     
         
    
            public MainPage()
            {
                this.InitializeComponent();
            }
    
           
    
            private async void Button_Click(object sender, RoutedEventArgs e)
            {
                if (_client.Connected == false)
                {
                    await _client.ConnectAsync("10.0.0.20", 23);
                    if (_client.Connected)
                    {
                        Debug.WriteLine(_client.Connected);
                        in_stream = _client.GetStream();                   
                        rx_thread = new Thread(data_rx);
                        rx_thread.Start();
                    }
                }
            }
    
    
    
            private void data_rx()
            {
                byte[] bytes = new byte[1024];
                Byte[] data = new Byte[256];
                while (true)
                {
                    int bytesRead = in_stream.Read(bytes, 0, bytes.Length);
                    _clientResponse = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRead);
                    switch(_clientResponse)
                    {
                        case "login":
                            connected = false;
                            data = System.Text.Encoding.ASCII.GetBytes("userName\n");
                            in_stream.Write(data, 0, data.Length);
                            break;
                        case "password":
                            data = System.Text.Encoding.ASCII.GetBytes("Password\n");
                            in_stream.Write(data, 0, data.Length);
                            break;
                        case "Success":
                            connected = true;
                            break;
                        case "~":
                            ProcessFeedback(_clientResponse);
                            break;
                        default:
                            break;
    
                    }
                }
            }
    
            private void ProcessFeedback(string clientResponse)
            {
               Debug.WriteLine(clientResponse);
            }
    
            private void SendCommand(string cmd)
            {
                if (connected)
                {
                    Byte[] data = new Byte[256];
                    data = System.Text.Encoding.ASCII.GetBytes(cmd);
                    in_stream.Write(data, 0, data.Length);
                }
                else if (!connected)
                {
                   Debug.WriteLine("Not Connected to device");
                }
            }
        }

    Wednesday, June 26, 2019 1:16 AM

Answers

  • Hi,
    if you use a singleton pattern of ViewModel you need to assign the DataContext in every page like in the following demo:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Windows.Input;
    using System.Xml.Serialization;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class Page15 : Page
      {
        public Page15()
        {
          this.InitializeComponent();
          this.DataContext = Page15VM.Instance;
        }
      }
      public class Page15VM : INotifyPropertyChanged
      {
        // singleton pattern
        private static Page15VM _instance = null;
        public static Page15VM Instance { get { if (_instance == null) _instance = new Page15VM; return _instance; } }
    
        private int nr = 0;
        private string hostName = "127.0.0.1";
        private int serverPort = 5000;
        public string Display { get; set; } = "<empty>";
        public ICommand Cmd { get { return new RelayCommand(CmdExec); } }
        private async void CmdExec(object obj)
        {
          try
          {
            TcpClient client = new TcpClient();
            await client.ConnectAsync(hostName, serverPort);
    
            // Data object for sending
            nr++;
            Page15Data d1 = new Page15Data()
            {
              ID = nr,
              Info1 = $"Line {nr}",
              Info2 = "request"
            };
    
            // Data object for receiving
            Page15Data d2 = null;
    
            using (NetworkStream str = client.GetStream())
            {
              using (StreamWriter wrt = new StreamWriter(str))
              {
                str.ReadTimeout = 600;
                using (StreamReader rdr = new StreamReader(str))
                {
                  string req = GetXML<Page15Data>(d1);
                  await wrt.WriteLineAsync(req);
                  await wrt.FlushAsync();
                  string resp = await rdr.ReadLineAsync();
                  d2 = GetData<Page15Data>(resp);
                  Display += $"{Environment.NewLine}Received Object from Server ID:{ d2.ID}, Info1: { d2.Info1}, Info2: { d2.Info2}";
                }
              }
            }
          }
          catch (Exception ex)
          {
            Display = ex.ToString();
          }
          OnPropertyChanged(nameof(Display));
        }
    
        private string GetXML<T>(T obj)
        {
          MemoryStream ms = new MemoryStream();
          XmlSerializer ser = new XmlSerializer(typeof(T));
          ser.Serialize(ms, obj);
          string res = Encoding.UTF8.GetString(ms.ToArray());
          res = res.Replace(Environment.NewLine, "");
          return res;
        }
    
        private T GetData<T>(string xml)
        {
          MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));
          XmlSerializer ser = new XmlSerializer(typeof(T));
          return (T)ser.Deserialize(ms);
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      [XmlRoot("Root")]
      public class Page15Data
      {
        [XmlElement("ID")] public int ID { get; set; }
        [XmlElement("Info1")] public string Info1 { get; set; }
        [XmlElement("Info2")] public string Info2 { get; set; }
      }
    }
    


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Marked as answer by CMCTS Monday, July 1, 2019 10:57 AM
    Sunday, June 30, 2019 3:44 PM

All replies

  • Hi,

    First, generally in UWP apps, we'd use StreamSocket for TCP connections instead of using TcpClient. And SteamSocketListener is used listening for an incoming network connection using a TCP stream socket. Also for threading and async programming, in UWP apps, we'd use Asynchronous APIs or create a task instead of creating a thread deliberately. 

    So I'd suggest you to use the SteamSocket in the UWP apps. Here is an official sample for this:StreamSocket Sample

    Best regards,

    Roy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, June 26, 2019 6:29 AM
    Moderator
  • The problem I have is that I need to make a connection and maintain it.  Maybe I am wrong but I though the streamsocket listener waits for an incoming connection. and then disconnects.  Is there a way to create and keep the connection open with streamsocket?

    I have used streamsocket before in other applications where I dod not need to open and maintain a connection and it works great. But not sure it can work in this scenario.

    Wednesday, June 26, 2019 9:44 AM
  • Hi,
    if you want to use TcpClient try this demo:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Windows.Input;
    using System.Xml.Serialization;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class Page15 : Page
      {
        public Page15()
        {
          this.InitializeComponent();
        }
      }
      public class Page15VM : INotifyPropertyChanged
      {
        private int nr = 0;
        private string hostName = "127.0.0.1";
        private int serverPort = 5000;
        public string Display { get; set; } = "<empty>";
        public ICommand Cmd { get { return new RelayCommand(CmdExec); } }
        private async void CmdExec(object obj)
        {
          try
          {
            TcpClient client = new TcpClient();
            await client.ConnectAsync(hostName, serverPort);
    
            // Data object for sending
            nr++;
            Page15Data d1 = new Page15Data()
            {
              ID = nr,
              Info1 = $"Line {nr}",
              Info2 = "request"
            };
    
            // Data object for receiving
            Page15Data d2 = null;
    
            using (NetworkStream str = client.GetStream())
            {
              using (StreamWriter wrt = new StreamWriter(str))
              {
                str.ReadTimeout = 600;
                using (StreamReader rdr = new StreamReader(str))
                {
                  string req = GetXML<Page15Data>(d1);
                  await wrt.WriteLineAsync(req);
                  await wrt.FlushAsync();
                  string resp = await rdr.ReadLineAsync();
                  d2 = GetData<Page15Data>(resp);
                  Display += $"{Environment.NewLine}Received Object from Server ID:{ d2.ID}, Info1: { d2.Info1}, Info2: { d2.Info2}";
                }
              }
            }
          }
          catch (Exception ex)
          {
            Display = ex.ToString();
          }
          OnPropertyChanged(nameof(Display));
        }
    
        private string GetXML<T>(T obj)
        {
          XmlSerializer ser = new XmlSerializer(obj.GetType());
          MemoryStream ms = new MemoryStream();
          ser.Serialize(ms, obj);
          string res = Encoding.UTF8.GetString(ms.ToArray());
          res = res.Replace(Environment.NewLine, "");
          return res;
        }
    
        private T GetData<T>(string xml)
        {
          MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));
          XmlSerializer ser = new XmlSerializer(typeof(T));
          return (T)ser.Deserialize(ms);
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      [XmlRoot("Root")]
      public class Page15Data
      {
        [XmlElement("ID")] public int ID { get; set; }
        [XmlElement("Info1")] public string Info1 { get; set; }
        [XmlElement("Info2")] public string Info2 { get; set; }
      }
    }


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks



    Wednesday, June 26, 2019 9:47 AM
  • I finally was able to get the client built and created a dll so I could use it in y main application.

    The problem is now I have 2 pages of mf my application that need to access different parts of the dll but also have to share other data contained in the dll.

    I have tried it all on just one page and everything works. However I want to have a second page that does certain things to the dll data.

    Basically I want to share the same instance of the dll between the two classes(pages).


    Sunday, June 30, 2019 2:50 PM
  • Hi,
    my demo use a ViewModel. You can use the same instance of the ViewModel in several pages. To achieve this you can either use a resource of the application or a singleton.

    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Sunday, June 30, 2019 3:13 PM
  • Forgive the lack of experience on this. Could you simplify your sample. I Want to use 1 instance of my dll shared between multiple classes
    Sunday, June 30, 2019 3:22 PM
  • Hi,
    if you use a singleton pattern of ViewModel you need to assign the DataContext in every page like in the following demo:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Windows.Input;
    using System.Xml.Serialization;
    using Windows.UI.Xaml.Controls;
    
    // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238
    
    namespace App1
    {
      /// <summary>
      /// An empty page that can be used on its own or navigated to within a Frame.
      /// </summary>
      public sealed partial class Page15 : Page
      {
        public Page15()
        {
          this.InitializeComponent();
          this.DataContext = Page15VM.Instance;
        }
      }
      public class Page15VM : INotifyPropertyChanged
      {
        // singleton pattern
        private static Page15VM _instance = null;
        public static Page15VM Instance { get { if (_instance == null) _instance = new Page15VM; return _instance; } }
    
        private int nr = 0;
        private string hostName = "127.0.0.1";
        private int serverPort = 5000;
        public string Display { get; set; } = "<empty>";
        public ICommand Cmd { get { return new RelayCommand(CmdExec); } }
        private async void CmdExec(object obj)
        {
          try
          {
            TcpClient client = new TcpClient();
            await client.ConnectAsync(hostName, serverPort);
    
            // Data object for sending
            nr++;
            Page15Data d1 = new Page15Data()
            {
              ID = nr,
              Info1 = $"Line {nr}",
              Info2 = "request"
            };
    
            // Data object for receiving
            Page15Data d2 = null;
    
            using (NetworkStream str = client.GetStream())
            {
              using (StreamWriter wrt = new StreamWriter(str))
              {
                str.ReadTimeout = 600;
                using (StreamReader rdr = new StreamReader(str))
                {
                  string req = GetXML<Page15Data>(d1);
                  await wrt.WriteLineAsync(req);
                  await wrt.FlushAsync();
                  string resp = await rdr.ReadLineAsync();
                  d2 = GetData<Page15Data>(resp);
                  Display += $"{Environment.NewLine}Received Object from Server ID:{ d2.ID}, Info1: { d2.Info1}, Info2: { d2.Info2}";
                }
              }
            }
          }
          catch (Exception ex)
          {
            Display = ex.ToString();
          }
          OnPropertyChanged(nameof(Display));
        }
    
        private string GetXML<T>(T obj)
        {
          MemoryStream ms = new MemoryStream();
          XmlSerializer ser = new XmlSerializer(typeof(T));
          ser.Serialize(ms, obj);
          string res = Encoding.UTF8.GetString(ms.ToArray());
          res = res.Replace(Environment.NewLine, "");
          return res;
        }
    
        private T GetData<T>(string xml)
        {
          MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xml));
          XmlSerializer ser = new XmlSerializer(typeof(T));
          return (T)ser.Deserialize(ms);
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
    
      [XmlRoot("Root")]
      public class Page15Data
      {
        [XmlElement("ID")] public int ID { get; set; }
        [XmlElement("Info1")] public string Info1 { get; set; }
        [XmlElement("Info2")] public string Info2 { get; set; }
      }
    }
    


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    • Marked as answer by CMCTS Monday, July 1, 2019 10:57 AM
    Sunday, June 30, 2019 3:44 PM
  • Thank you. I will try to see if I can use this concept in my application.
    Sunday, June 30, 2019 5:59 PM
  • So I could use the singleton pattern inside the dll?

    Thus only one instance can be created in the project, correct?

    Monday, July 1, 2019 10:57 AM
  • Thank you. I was able to use the Singleton method and it works as I was expecting.
    Friday, July 5, 2019 12:39 PM