locked
StreamSocket.InputStream always empty RRS feed

  • Question

  • Hello,

    I apologize if this is not the correct forum - this is my first time using one.

    I am attempting to write a UWP app that listens on a TCP port, and allows up to 4 simultaneous connections with client devices.

    I have a StreamSocketListener that I create on the main UI thread:

    public void StartListening(HostName LocalAdapter, ushort LocalPort)
            {
                Listener = new StreamSocketListener();
                Listener.ConnectionReceived += Listener_ConnectionReceived;
                Listener.BindEndpointAsync(LocalAdapter, LocalPort.ToString());
                
            }

    When a client sends a connection request, Listener_ConnectionReceived fires properly and I hand off the returned socket to a new task:

     
     private void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
            {
               
                Task t = new Task(StartupTCPSession, args, TaskCreationOptions.LongRunning);
                t.Start();
            }
            private Action<object> StartupTCPSession = (object ConnectionArgs) =>
            {
                StreamSocketListenerConnectionReceivedEventArgs args = (StreamSocketListenerConnectionReceivedEventArgs)ConnectionArgs;
                TCPSession NewSession = new TCPSession(EIPConnectionMonitor.GetSessionID(), args);
                NewSession.RunSession();
            };

    The TCPSession Class:

    class TCPSession
        {
            
            private StreamSocket Socket;
            public readonly uint SessionID;
            private EIPConnectionMonitor Parent;
            private bool shutdownSession;
            private Task SessionTask;
            private DataReader Reader;
            private DataWriter Writer;
    
            public TCPSession(uint sessionID, StreamSocketListenerConnectionReceivedEventArgs ConnectionInfo)
            {
                SessionID = sessionID;
                Socket = ConnectionInfo.Socket;
                shutdownSession = false;
            }
    
            public void RunSession()
            {
                Reader = new DataReader(Socket.InputStream);
                Writer = new DataWriter(Socket.OutputStream);
                while (!shutdownSession)
                {
                    if (Reader.UnconsumedBufferLength>0) //If I set a breakpoint here, the code always stops, which I take as the code is executing
                    {
                        byte[] RecData = new byte[Reader.UnconsumedBufferLength]; //a breakpoint here never hits
                        Reader.ReadBytes(RecData);//should read buffer
                        
                    }
                    else
                    {
                        Task.Delay(5);
                    }
                }
            }
    
            public void ShutdownSession()
            {
                shutdownSession = true;
            }
    
            
        }
     

    When I run this code, the client (a PLC) issues a connection request, which my code sees via the Listener_ConnectionReceived function being called.

    I monitor the connection using Wireshark and I can see that the client sends the exact TCP packet I am expecting, to the expected port, but the DataReader never indicates that there is any data available.

    The really crazy thing is that this exact code worked flawlessly for 5 days and then stopped.  I thought I might be doing something wrong with threading (or that my hardware failed), so I wrote a simple Windows Forms app that uses the same threading structure but uses the System.Net.Sockets namespace instead of the Windows.Networking.Sockets namespace:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Net;
    using System.Net.Sockets;
    using System.IO;
    
    
    namespace WindowsFormsApp1
    {
        class TCPSession
        {
           
            private TcpListener Listener;
            private Socket SS;
            public readonly uint SessionID;
            private bool shutdownSession;
            private Task SessionTask;
           
    
            public TCPSession(uint sessionID, Socket socket)
            {
                SessionID = sessionID;
                SS = socket;
                
            }
            public void RunSession()
            {
                while (true)
                {
                    if (SS.Available>0)
                    {
                        byte[] NewData = new byte[SS.Available]; //a breakpoint here hits as expected when client sends message
                        SS.Receive(NewData);
                    }
                    Task.Delay(5);
                }
            }
        }
        class EIPConnectionMonitor
        {
            private TcpListener Listener;
            private static UInt32 NextSessionID;
            private static UInt32 SessionOffset;
            public EIPConnectionMonitor()
            {
                NextSessionID = 0;
                Random r = new Random();
                SessionOffset = (uint)r.Next(0x10000, 0x7fff0000);
            }
            public async void ListenForConnections()
            {
                int ListenPort = 0xaf12;
                IPAddress LocalIPAddress = IPAddress.Parse("10.57.45.5");
                Listener = new TcpListener(LocalIPAddress, ListenPort);
                Listener.Start();
                while (true)
                {
                    Socket NewSocket = await Listener.AcceptSocketAsync();
                    Task t = new Task(StartupTCPSession, NewSocket, TaskCreationOptions.LongRunning);
                    t.Start();
                }
                
    
            }
     
            public static UInt32 GetSessionID()
            {
                NextSessionID += 1;
                if (NextSessionID >= 0x1000)
                    NextSessionID = 0x1;
                return ((SessionOffset & 0xffff0000) | NextSessionID);
            }
    
            
            private Action<object> StartupTCPSession = (object socket) =>
            {
                TCPSession NewSession = new TCPSession(EIPConnectionMonitor.GetSessionID(), (Socket)socket);
                NewSession.RunSession();
            };
    
        }
    }

    I run this code on the same machine (using the same Ethernet adapter), and it receives data from the client as I would expect.

    I'm assuming I accidently changed some project setting that is causing my problem, but I have no idea what it could be.  My UWP app has the following capabilities checked in the Package.appxmanifest file: 

    • Private Networks (Client & Server)
    • Internet (Client & Server)

    I am targeting the Universal Windows, Windows 10 Fall Creators update (10.0 build 16299) - that is also my min version.

    I've also used a different Ethernet adapter, but it does not change the results.

    I've been pulling my hair out for 3 days trying to find forum posts that tell me what my problem is, but I can't find a solution.

    Any assistance would be greatly appreciated!

    Saturday, November 18, 2017 2:13 PM

All replies

  • I also forgot to point out that I disabled my firewall protection as a test and it did not change the results.
    Saturday, November 18, 2017 2:20 PM
  • Hi iamojo

    I used the official sample StreamSocket to test about this issue. In my test, I reproduced your issue. When the ConnectionReceived  event is triggered, I checked the Socket.InputStream using DataReader, the UnconsumedBufferLength is 0. This is because it is the first connection and you haven’t sent any data. To receive data, you might need to create a While(true) loop, reading the data in the loop as the sample does.

    You could refer this:

      /// <summary>
            /// Invoked once a connection is accepted by StreamSocketListener.
            /// </summary>
            /// <param name="sender">The listener that accepted the connection.</param>
            /// <param name="args">Parameters associated with the accepted connection.</param>
            private async void OnConnection(
                StreamSocketListener sender,
                StreamSocketListenerConnectionReceivedEventArgs args)
            {
                DataReader reader = new DataReader(args.Socket.InputStream);
                try
                {
                    while (true)
                    {
                        // Read first 4 bytes (length of the subsequent string).
                        uint sizeFieldCount = await reader.LoadAsync(sizeof(uint));
                        if (sizeFieldCount != sizeof(uint))
                        {
                            // The underlying socket was closed before we were able to read the whole data.
                            return;
                        }
     
                        // Read the string.
                        uint stringLength = reader.ReadUInt32();
                        uint actualStringLength = await reader.LoadAsync(stringLength);
                        //This is your code
                        byte[] RecData = new byte[reader.UnconsumedBufferLength]; //a breakpoint here never hits
                        reader.ReadBytes(RecData);//should read buffer
     
                        if (stringLength != actualStringLength)
                        {
                            // The underlying socket was closed before we were able to read the whole data.
                            return;
                        }
     
                        // Display the string on the screen. The event is invoked on a non-UI thread, so we need to marshal
                        // the text back to the UI thread.
                        NotifyUserFromAsyncThread(
                            String.Format("Received data: \"{0}\"", reader.ReadString(actualStringLength)),
                            NotifyType.StatusMessage);
                    }
                }

    For more information, please refer the Scenario1_start of the StreamSocket.

    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.


    Tuesday, November 21, 2017 3:15 AM
  • @iamojo

    I have updated my reply. Please check it.

    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.

    Thursday, November 23, 2017 8:06 AM
  • Hi Roy,

    Thank you for looking into this.  When I changed my code to use the await operator, it started receiving messages:

    class TCPSession
        {
            
            private StreamSocket Socket;
            public readonly uint SessionID;
            private EIPConnectionMonitor Parent;
            private bool shutdownSession;
            private Task SessionTask;
            private DataReader Reader;
            private DataWriter Writer;
    
            public TCPSession(uint sessionID, StreamSocketListenerConnectionReceivedEventArgs ConnectionInfo)
            {
                SessionID = sessionID;
                Socket = ConnectionInfo.Socket;
                shutdownSession = false;
            }
    
            public async void RunSession()
            {
                Reader = new DataReader(Socket.InputStream);
                Writer = new DataWriter(Socket.OutputStream);
                while (!shutdownSession)
                {
                    uint test = await Reader.LoadAsync(4);
                    uint Data = Reader.ReadUInt32();
                }
            }
    
            public void ShutdownSession()
            {
                shutdownSession = true;
            }
    
            
        }
    
    

    I did hit the breakpoint on reception of data with this simple code.  I have to admit that I am still confused why my original code did not work (actually it did work for a number of days) - I am continuously checking the unconsumed buffer length, and if it is zero I execute the Task.Delay(5) line of code, and the buffer is checked again.

    I will revise my code to utilize the await operator (it's a better solution than my original attempt as well) and hopefully it continues to operate for me without any more hiccups.

    Thank you very much for your assistance!

    Matt

    Sunday, November 26, 2017 2:51 PM
  • @iamojo

    Have you resolved your problem? Does the code working well in you side?

    Please feel free to contact us if you have any problems.

    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.

    Thursday, November 30, 2017 2:12 AM