通常我可以做这样的事情来用流数据填充字节数组:
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成为类的成员变量的情况下访问已读入的字节?显然我不想这样做,因为有多个连接,它们都有不同的值..
我觉得我在这里遗漏了一些明显的东西......
答案 0 :(得分: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);
//..
}
}
答案 1 :(得分: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
返回的字节数。
另外,我还没有对它进行过测试,但是我会在后续的4个字节中读取Read
的后续调用。