必须读取两次数据?我错过了什么?
本文关键字:数据 错过了 什么 两次 读取 | 更新日期: 2023-09-27 18:09:08
通常我可以这样做,用流数据填充字节数组:
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()
:
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);
//..
}
}
在MSDN(我可以找到,NetworkStream)上似乎没有完整的例子。EndRead有一些代码(http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.endread(v=VS.90).aspx)。
本教程有一个完整的例子:http://www.switchonthecode.com/tutorials/csharp-tutorial-asynchronous-stream-operations
简而言之,在调用clientStream.EndRead
之后,您的原始缓冲区dataLength
应该已经填充了EndRead
返回的字节数。
同样,我还没有测试它,但我认为随后对Read
的调用将读取流的下一个4字节。