Search code examples
tcpuwpclient-serverhololens

How can I read byte array coming from server in UWP app?


I have a client-server app. The client is HoloLens 2 and the server is unity running on PC. I have created a socket using HoloLens but I can't read the byte array on HoloLens. In the connect method _inputStream and _outputStream are System.IO.Streams.

PC client uses System.Net.Sockets.TcpClient, System.Net.Sockets.NetworkStream but UWP (HoloLens) uses Windows.Networking.Sockets.StreamSocket.

In the ReceiveCallback I have an issue with int byteLenght = _inputStream.EndRead(result); When I tried this code on HoloLens I got the exception: "System.ArgumentException: The specified AsyncResult does not correspond to any outstanding IO operation". But I tested it with PC client (System.Net.Socket) and everything works fine.

Btw, I gave all related permissions.

How can I read byte array in UWP app?

Update:

#if UNITY_EDITOR
        private void ConnectUWP(string host, string port)
#else
        private async void ConnectUWP(string host, string port)
#endif
        {
#if UNITY_EDITOR
            errorStatus = "UWP TCP client used in Unity!";
#else
        try
        {
            socket = new Windows.Networking.Sockets.StreamSocket();
            Windows.Networking.HostName serverHost = new Windows.Networking.HostName(host);
            _receivedData = new Packet();
            _receiveBuffer = new byte[DataBufferSize];
            await socket.ConnectAsync(serverHost, port);
            successStatus = "Connected!";

             _outputStream = socket.OutputStream.AsStreamForWrite();
             //_streamWriter = new StreamWriter(_outputStream) { AutoFlush = true };
             
             _inputStream = socket.InputStream.AsStreamForRead();
             Task.Run(() => StreamToBytes(socket.InputStream));

        }
        catch (Exception e)
        {
            errorStatus = e.ToString();
            Debugger.GetComponent<TextMeshPro>().text += "\n Exception: " + errorStatus;
        }
#endif

#if !UNITY_EDITOR
        public async Task StreamToBytes(Windows.Storage.Streams.IInputStream stream)
        {
             using (var reader1 = new Windows.Storage.Streams.DataReader(stream))
             {
                reader1.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.ReadAhead;
                reader1.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
                reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;

                //InBuffer is always 256, 
                //even if there is more data waiting. If I put a task.delay in it will always return 25
                try
                {
                    await reader1.LoadAsync(256);
                }
                catch (Exception ex)
                {
                    //..
                }

                while (reader1.UnconsumedBufferLength > 0)
                {
                    var bytes1 = new byte[reader1.UnconsumedBufferLength];
                    reader1.ReadBytes(bytes1);
                    _receivedData.Reset(await HandleData(bytes1));
                    await reader1.LoadAsync(256); 
                }
                reader1.DetachStream();
              }
        }

            private async Task<bool> HandleData(byte[] data)
            {
                int packetLength = 0;

                _receivedData.SetBytes(data);

                if (_receivedData.UnreadLength() >= 4)
                {
                    // If client's received data contains a packet
                    packetLength = _receivedData.ReadInt();

                    if (packetLength <= 0)
                    {
                        // If packet contains no data
                        return true; // Reset receivedData instance to allow it to be reused
                    }
                }

                while (packetLength > 0 && packetLength <= _receivedData.UnreadLength())
                {
                    // While packet contains data AND packet data length doesn't exceed the length of the packet we're reading
                    byte[] packetBytes = _receivedData.ReadBytes(packetLength);
                    
                    ThreadManager.ExecuteOnMainThread(() =>
                    {
                        using (Packet packet = new Packet(packetBytes))
                        {
                            int packetId = packet.ReadInt();
                            _packetHandlers[packetId](packet); // Call appropriate method to handle the packet
                        }
                    });

                    packetLength = 0; // Reset packet length
                    if (_receivedData.UnreadLength() >= 4)
                    {
                        // If client's received data contains another packet
                        packetLength = _receivedData.ReadInt();
                        if (packetLength <= 0)
                        {
                            // If packet contains no data
                            return true; // Reset receivedData instance to allow it to be reused
                        }
                    }
                }

                if (packetLength <= 1)
                {
                    return true; // Reset receivedData instance to allow it to be reused
                }

                return false;
            }
#endif

Solution

  • I tried everything for TCP but TCP is nearly impossible for HoloLens with UWP app. So I tried UDP and it works perfectly (https://github.com/mbaytas/HoloLensUDP). I hope Microsoft put a TCP example for HoloLens 1 and 2 in near future. Thanks Nico for your help.