C# 必须读入数据两次吗?我错过了什么?
通常我可以这样做,用流数据填充字节数组:C# 必须读入数据两次吗?我错过了什么?,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,通常我可以这样做,用流数据填充字节数组: byte[] dataLength = new byte[4]; clientStream.Read(dataLength, 0, dataLength.Length); 这将填充字节数组。。但是,我一直在尝试异步调用,我的代码如下所示: byte[] dataLength = new byte[4]; clientStream.BeginRead(dataLength, 0, dataLength.Length, Read, clientStre
byte[] dataLength = new byte[4];
clientStream.Read(dataLength, 0, dataLength.Length);
这将填充字节数组。。但是,我一直在尝试异步调用,我的代码如下所示:
byte[] dataLength = new byte[4];
clientStream.BeginRead(dataLength, 0, dataLength.Length, Read, clientStream);
private void Read(IAsyncResult async)
{
NetworkStream clientStream = (NetworkStream)async.AsyncState;
clientStream.EndRead(async);
byte[] dataLength = new byte[4]; // ..?
clientStream.Read(dataLength, 0, dataLength.Length); // Have to re-read in data with synchronous version?..
int result = BitConverter.ToInt32(dataLength, 0);
}
我觉得这完全是。。错。如果您只需要在回调中同步地重新读取异步调用,那么异步调用的意义何在?如何访问已读取的字节,而不使dataLength成为类的成员变量?显然我不想这样做,因为有不止一个连接,它们都有不同的值
我觉得我错过了一些显而易见的东西。你不必再看一遍——当你打电话的时候
clientStream.EndRead(async);
它返回已读取的字节数,因此您需要执行以下操作:
int bytesRead = clientStream.EndRead(async);
此时,您的缓冲区已被这些字节填满,以同步方式从流中读取只会读取更多字节
如果不想将缓冲区设为实例变量,则可以使用带有委托的闭包:
byte[] buffer = new byte[4];
clientStream.BeginRead(buffer, 0, buffer.Length, (IAsyncResult async) =>
{
int bytesRead = clientStream.EndRead(async);
if (bytesRead == 4)
{
int result = BitConverter.ToInt32(buffer, 0);
//..
}
}, clientStream);
编辑:
更好的解决方案可能是以自定义类的形式放置所有状态,并将其传递到BeginRead()
:
MSDN上似乎没有完整的示例(我可以找到,NetworkStream.EndRead有一些代码) 本教程提供了一个完整的示例: 简而言之,在调用
clientStream.EndRead
之后,原始缓冲区dataLength
应该已经填充了EndRead
返回的字节数
另外,我还没有对它进行测试,但是我想后续调用
Read
将读取流的下4个字节。谢谢您的回答。然而,“如果你不想让你的缓冲区成为一个实例变量”是什么意思?如果我一次有多个连接,实例变量难道不起作用吗?你说得好像这是可能的?还有,有没有什么办法不关闭它?如果能够将闭包代码放在一个单独的函数中就好了。另外,如果使用这样的闭包,为什么还要传入clientStream作为对象数据的最后一个参数,并将其强制转换回NetworkStream?既然clientStream在范围内,为什么不直接访问它呢?我注意到在你做了这个(NetworkStream)async.AsyncState
之后,你甚至从未使用过这个变量,那么为什么还要传递它呢?@John Smith:是的,这是一个经过疏忽编辑的答案,并添加了一个解决方案,该解决方案应该更好(自定义状态对象)BrokenGlass:感谢更新。但是仍然想知道,当他们必须从回调中访问字节时,总是这样吗?似乎是一件很平常的事。。这真的是最好的方法吗?
public class StreamState
{
public byte[] Buffer { get; set; }
public NetworkStream Stream { get; set; }
}
clientStream.BeginRead(buffer, 0, buffer.Length, Read, new StreamState { Buffer = buffer, Stream = clientStream });
private void Read(IAsyncResult async)
{
StreamState state = (StreamState) async.AsyncState;
int bytesRead = state.Stream.EndRead(async);
if (bytesRead == 4)
{
int result = BitConverter.ToInt32(state.Buffer, 0);
//..
}
}