У меня есть клиент-серверное приложение. Клиент — это 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





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();
}
Хорошо, я понял, я обновил ответ по делу, который использует DataReader для чтения байтов.
Привет, Нико, я попробовал твой ответ, и на этот раз нет никаких исключений, однако он не работает. После reader1.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian; я ничего не получил: ни исключения, ни массива байтов. Я потерял отладку в await reader1.LoadAsync(256); . Я использую System.Net.Sockets и System.Net.Sockets.NetworkStream на стороне сервера и передаю данные в виде массива байтов. Можем ли мы сказать, что если я хочу отправить массив байтов с сервера на клиент, в зависимости от клиентского устройства мне нужно изменить поток? Однако мой сервер должен работать на ПК, и я не могу запустить код UWP на сервере. Связано с этим?
Использование System.Net.Sockets на сервере и использование Windows.Networking.Sockets.StreamSocket в клиенте HoloLens не является ключевым моментом. массив байтов — это универсальные данные между сервером и клиентом. Вы добавили ключевое слово async в метод?
Я обновил свой вопрос. Я рад это слышать, иначе это не имело бы для меня смысла. Да, я использовал асинхронность в своем методе.
Я проверил ваш код, я обнаружил, что вы пропустили await ключевое слово в этой строке try { reader1.LoadAsync(256); }
Да, вы правы, но результат не изменился - я ничего не получил. Я тестировал с единством код. Самое смешное, что хотя я сменил платформу на UWP, в Unity по-прежнему используется System.Net.Sockets.TcpClient. Я провел небольшое исследование, и люди сказали: «Вы не можете запустить Windows lib в редакторе Unity». Думаю, единственный способ протестировать код — развернуть его на HoloLens.
Кажется, я нашел проблему. Проблема в том, что await reader1.LoadAsync(256); //InBuffer is always 256 должен быть фиксированный размер, а не 256!. Мы дали 256, но фактические данные в моем случае 47. Если я поставил 47 лайк await reader1.LoadAsync(47), это работает. Как я могу получить длину потока?
256 - это размер буфера, но не длина потока, не имеет значения, установите длину буфера как 256 или 47. И ваш входной поток не может быть найден, мы не можем получить общую длину. если может работать небольшая длина буфера, попробуйте установить буфер равным 16.
Но я не хочу фиксированный буфер таким образом. Каждый входящий поток должен нести данные разного размера, и я должен иметь возможность читать каждый поток n-размера.
Я нашел причину, по которой reader1.LoadAsync(256) не вызывается, если вы установите InputStreamOptions на ReadAhead, когда буфер 256 заполнится, он сделает следующий шаг. пожалуйста, попробуйте InputStreamOptions как Partial
Я пробовал все для TCP, но TCP почти невозможен для HoloLens с приложением UWP. Итак, я попробовал UDP, и он отлично работает (https://github.com/mbaytas/HoloLensUDP). Я надеюсь, что в ближайшем будущем Microsoft представит пример TCP для HoloLens 1 и 2. Спасибо Нико за помощь.
Привет, спасибо за ваш ответ. Я попробовал, но получил другое исключение: «System.NotSupportedException: этот поток не поддерживает свойство «Длина», потому что его невозможно найти». Я использовал как «общедоступную асинхронную задачу <byte []> StreamToBytes (System.IO.Stream stream)». Вы предлагаете поток system.io.stream?