Как я могу прочитать массив байтов, поступающий с сервера в приложении UWP?

У меня есть клиент-серверное приложение. Клиент — это HoloLens 2, а сервер — это единство, работающее на ПК. Я создал сокет с помощью HoloLens, но не могу прочитать массив байтов в HoloLens. В методе подключения _inputStream и _outputStream являются System.IO.Streams.

Клиент ПК использует System.Net.Sockets.TcpClient, System.Net.Sockets.NetworkStream, но UWP (HoloLens) использует Windows.Networking.Sockets.StreamSocket.

В ReceiveCallback у меня возникла проблема с int byteLenght = _inputStream.EndRead(result); Когда я попробовал этот код на HoloLens, я получил исключение: «System.ArgumentException: указанный AsyncResult не соответствует какой-либо невыполненной операции ввода-вывода». Но я протестировал его с ПК-клиентом (System.Net.Socket), и все работает нормально.

Кстати, я дал все соответствующие разрешения.

Как я могу прочитать массив байтов в приложении UWP?

Обновлять:

#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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
160
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

When I tried this code on HoloLens I got the exception: "System.ArgumentException: The specified AsyncResult does not correspond to any outstanding IO operation".

Пожалуйста, обратитесь к документу метода BeginRead, В .NET Framework 4 и более ранних версиях для реализации асинхронных операций ввода-вывода необходимо использовать такие методы, как BeginRead и EndRead. Эти методы по-прежнему доступны в .NET Framework 4.5 для поддержки устаревшего кода; однако новые асинхронные методы, такие как ReadAsync, WriteAsync, CopyToAsync и FlushAsync, упрощают реализацию асинхронных операций ввода-вывода. Я полагаю, что этот старый API не может быть совместим с устройством HoloLens, поэтому попробуйте использовать ReadAsync для замены, как показано ниже.

 byte[] bytes = await StreamToBytes(_inputStream);
 public async Task<byte[]> StreamToBytes(Stream stream)
 {
     byte[] bytes = new byte[stream.Length];
     await stream.ReadAsync(bytes, 0, bytes.Length);
     stream.Seek(0, SeekOrigin.Begin);
     return bytes;
 }

Или следуйте официальной обработке, которая использует DataReader для чтения ReadBytes, для получения дополнительной информации см. потоковый сокет.

Обновлять

using (var reader1 = new DataReader(_inputStream)
{
    reader1.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;
    reader1.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
    reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;

    await reader1.LoadAsync(256); //InBuffer is always 256, 
                                  //even if there is more data waiting. If I put a task.delay in it will always return 25
    while (reader1.UnconsumedBufferLength > 0)
    {
        var bytes1 = new byte[reader1.UnconsumedBufferLength];
        reader1.ReadBytes(bytes1);
        await reader1.LoadAsync(256); 
    }
    reader1.DetachStream();
}

Привет, спасибо за ваш ответ. Я попробовал, но получил другое исключение: «System.NotSupportedException: этот поток не поддерживает свойство «Длина», потому что его невозможно найти». Я использовал как «общедоступную асинхронную задачу <byte []> StreamToBytes (System.IO.Stream stream)». Вы предлагаете поток system.io.stream?

Yunus Emre 17.03.2022 11:50

Хорошо, я понял, я обновил ответ по делу, который использует DataReader для чтения байтов.

Nico Zhu - MSFT 18.03.2022 04:22

Привет, Нико, я попробовал твой ответ, и на этот раз нет никаких исключений, однако он не работает. После reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; я ничего не получил: ни исключения, ни массива байтов. Я потерял отладку в await reader1.LoadAsync(256); . Я использую System.Net.Sockets и System.Net.Sockets.NetworkStream на стороне сервера и передаю данные в виде массива байтов. Можем ли мы сказать, что если я хочу отправить массив байтов с сервера на клиент, в зависимости от клиентского устройства мне нужно изменить поток? Однако мой сервер должен работать на ПК, и я не могу запустить код UWP на сервере. Связано с этим?

Yunus Emre 18.03.2022 15:24

Использование System.Net.Sockets на сервере и использование Windows.Networking.Sockets.StreamSocket в клиенте HoloLens не является ключевым моментом. массив байтов — это универсальные данные между сервером и клиентом. Вы добавили ключевое слово async в метод?

Nico Zhu - MSFT 21.03.2022 02:32

Я обновил свой вопрос. Я рад это слышать, иначе это не имело бы для меня смысла. Да, я использовал асинхронность в своем методе.

Yunus Emre 21.03.2022 12:00

Я проверил ваш код, я обнаружил, что вы пропустили await ключевое слово в этой строке try { reader1.LoadAsync(256); }

Nico Zhu - MSFT 22.03.2022 10:50

Да, вы правы, но результат не изменился - я ничего не получил. Я тестировал с единством код. Самое смешное, что хотя я сменил платформу на UWP, в Unity по-прежнему используется System.Net.Sockets.TcpClient. Я провел небольшое исследование, и люди сказали: «Вы не можете запустить Windows lib в редакторе Unity». Думаю, единственный способ протестировать код — развернуть его на HoloLens.

Yunus Emre 22.03.2022 11:26

Кажется, я нашел проблему. Проблема в том, что await reader1.LoadAsync(256); //InBuffer is always 256 должен быть фиксированный размер, а не 256!. Мы дали 256, но фактические данные в моем случае 47. Если я поставил 47 лайк await reader1.LoadAsync(47), это работает. Как я могу получить длину потока?

Yunus Emre 22.03.2022 16:52

256 - это размер буфера, но не длина потока, не имеет значения, установите длину буфера как 256 или 47. И ваш входной поток не может быть найден, мы не можем получить общую длину. если может работать небольшая длина буфера, попробуйте установить буфер равным 16.

Nico Zhu - MSFT 23.03.2022 03:25

Но я не хочу фиксированный буфер таким образом. Каждый входящий поток должен нести данные разного размера, и я должен иметь возможность читать каждый поток n-размера.

Yunus Emre 23.03.2022 11:00

Я нашел причину, по которой reader1.LoadAsync(256) не вызывается, если вы установите InputStreamOptions на ReadAhead, когда буфер 256 заполнится, он сделает следующий шаг. пожалуйста, попробуйте InputStreamOptions как Partial

Nico Zhu - MSFT 24.03.2022 09:28
Ответ принят как подходящий

Я пробовал все для TCP, но TCP почти невозможен для HoloLens с приложением UWP. Итак, я попробовал UDP, и он отлично работает (https://github.com/mbaytas/HoloLensUDP). Я надеюсь, что в ближайшем будущем Microsoft представит пример TCP для HoloLens 1 и 2. Спасибо Нико за помощь.

Другие вопросы по теме