2011-09-20 32 views
0

通常我可以做这样的事情来填充字节数组流数据:必须在数据中读取两次?我错过了什么?

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作为类的成员变量的情况下访问已读入的字节?很显然,我不想这样做,因为有多个连接,他们都有不同的价值观..

我觉得我缺少明显的东西在这里..

回答

2

你不必阅读这一遍 - 当你调用

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); 
     //.. 
    } 
} 
+0

感谢您的好解答。但是,如果“如果你不想让你的缓冲区成为实例变量”是什么意思?如果我一次有多个连接,那么实例变量不工作?你说话好像有可能吗?另外,有没有办法做到这一点没有关闭?能够将该闭包代码放置到单独的函数中会很好。 –

+0

另外,如果使用这样的闭包,为什么甚至会传入clientStream作为对象数据的最后一个参数并将其重新转换回NetworkStream?为什么不直接访问clientStream,因为它在范围之内?我注意到,在你做这个'(NetworkStream)async.AsyncState'后,你甚至从来没有使用过这个变量,所以为什么要传递它呢? –

+0

@John Smith:是的,这是一个疏忽 - 编辑的答案,并添加了一个更好的解决方案(自定义状态对象) – BrokenGlass

0

看起来并不完整e MSDN上的xamples(我可以找到,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个字节。

相关问题