Normally I can do something like this to fill up the byte array with stream data:
byte[] dataLength = new byte[4];
clientStream.Read(dataLength, 0, dataLength.Length);
And that fills up the byte array.. However, I've been experimenting with async calls and my code looks like this:
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);
}
Which I feel is completely.. wrong. What is the point of the 开发者_JS百科async call if you just have to read it all over again in the callback synchronously? How can I access the already read-in bytes without making the dataLength a member variable of the class? Obviously I don't want to do that because there is more than one connection and they all have different values..
I feel like I'm missing something obvious here..
You do not have to read it all over again - when you call
clientStream.EndRead(async);
it returns the number of bytes that have been read, so you will want to do:
int bytesRead = clientStream.EndRead(async);
At this point your buffer has been filled with those bytes, reading from the stream in a synchronous fashion would just read more bytes.
If you do not want to make your buffer an instance variable you could use a closure with a delegate instead:
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);
Edit:
A better solution might be to put all the state in form of a custom class and pass it in 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);
//..
}
}
There don't appear to be full examples on MSDN (that I could find, NetworkStream.EndRead has some code though http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.endread(v=VS.90).aspx).
This tutorial has a full example though: http://www.switchonthecode.com/tutorials/csharp-tutorial-asynchronous-stream-operations
In short though, after you've called clientStream.EndRead
, your original buffer dataLength
should have been populated with the number of bytes returned by EndRead
.
Also, I haven't tested it, but I would have though the subsequent call to Read
would read in the next 4 bytes of the stream.
精彩评论