如何在 UWP 应用程序中读取来自服务器的字节数组?
How can I read byte array coming from server in UWP app?
我有一个客户端-服务器应用程序。客户端是 HoloLens 2,服务器是 unity 运行 在 PC 上。我使用 HoloLens 创建了一个套接字,但无法读取 HoloLens 上的字节数组。在connect方法中_inputStream和_outputStream是System.IO.Streams.
PC 客户端使用 System.Net.Sockets.TcpClient
、System.Net.Sockets.NetworkStream
但 UWP (HoloLens) 使用 Windows.Networking.Sockets.StreamSocket
.
在 ReceiveCallback 中,我有一个问题 int byteLenght = _inputStream.EndRead(result);
当我在 HoloLens 上尝试这段代码时,我得到了异常:“System.ArgumentException:指定的 AsyncResult 不对应于任何未完成的 IO 操作”。但我用 PC 客户端 (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等方法来实现异步I/O操作.这些方法在 .NET Framework 4.5 中仍然可用,以支持遗留代码;但是,新的异步方法,例如 ReadAsync、WriteAsync、CopyToAsync 和 FlushAsync,可以帮助您更轻松地实现异步 I/O 操作。 我想这个旧的 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,更多代码请参考streamsocket.
更新
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();
}
我为 TCP 尝试了一切,但 TCP 对于带有 UWP 应用程序的 HoloLens 几乎是不可能的。所以我尝试了 UDP,它运行良好 (https://github.com/mbaytas/HoloLensUDP)。我希望微软在不久的将来为 HoloLens 1 和 2 提供一个 TCP 示例。感谢 Nico 的帮助。
我有一个客户端-服务器应用程序。客户端是 HoloLens 2,服务器是 unity 运行 在 PC 上。我使用 HoloLens 创建了一个套接字,但无法读取 HoloLens 上的字节数组。在connect方法中_inputStream和_outputStream是System.IO.Streams.
PC 客户端使用 System.Net.Sockets.TcpClient
、System.Net.Sockets.NetworkStream
但 UWP (HoloLens) 使用 Windows.Networking.Sockets.StreamSocket
.
在 ReceiveCallback 中,我有一个问题 int byteLenght = _inputStream.EndRead(result);
当我在 HoloLens 上尝试这段代码时,我得到了异常:“System.ArgumentException:指定的 AsyncResult 不对应于任何未完成的 IO 操作”。但我用 PC 客户端 (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等方法来实现异步I/O操作.这些方法在 .NET Framework 4.5 中仍然可用,以支持遗留代码;但是,新的异步方法,例如 ReadAsync、WriteAsync、CopyToAsync 和 FlushAsync,可以帮助您更轻松地实现异步 I/O 操作。 我想这个旧的 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,更多代码请参考streamsocket.
更新
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();
}
我为 TCP 尝试了一切,但 TCP 对于带有 UWP 应用程序的 HoloLens 几乎是不可能的。所以我尝试了 UDP,它运行良好 (https://github.com/mbaytas/HoloLensUDP)。我希望微软在不久的将来为 HoloLens 1 和 2 提供一个 TCP 示例。感谢 Nico 的帮助。