NetworkStream BeginRead and EndRead Confusion

hopeful

Member
Joined
Jun 25, 2009
Messages
7
Location
New Zealand
Programming Experience
10+
hi,

I am confused about the operation of the BeginRead and EndRead methods with respect to the way the buffer parameters in the BeginRead method are used.

Firstly, there appears to be a serious problem in the code sample for the EndRead method (appears in version 2 and in 3.5 possible all versions).

This has been noticed before (see link below):

http://www.vbdotnetforums.com/net-sockets/14938-can-someone-explain-code-snippet-msdn-networkstream-endread.html

If you take the code examples for the BeginRead and EndRead methods together (and they appear to be intended to fit together), then my second point of confusion is regarding how the buffer parameter in the BeginRead parameter is used:

1. Within the callback function BeginRead is called within a loop. It populates the local myReadBuffer each time, but doesn't do anything with the data that is presumably placed into myReadBuffer.

2. Each call to BeginRead (in 1 above) is followed by a callback to EndRead, but EndRead doesn't have access to the buffer that was passed to the corresponding BeginRead call (or if it does the callback function in the code example certainly isn't using it).

3. So it appears that any data read by the loop within the callback function will be lost.

4. Furthermore, what data ends up in the buffer that was passed to the initial call to BeginRead? Even though there were multiple calls to BeginRead within the callback function (each populating a different buffer), does the buffer passed to the initial BeginRead call somehow magically get populated with ALL the data that was read (by the multiple calls to BeginRead within the callback function)? If so how does this happen? If not then what purpose does the buffer passed to the initial BeginRead serve?

In other code examples I have seen the initial BeginRead call and the BeginRead call within the callback function are passed the same buffer variable. This seems to me to be the only way for the methods to be used that makes any sense, in which case within the BeginRead loop in in the callback function you would have to be careful to copy the data out before each call to BeginRead otherwise it would get overwritten. ADDED: or you would have to pass a different offset value to each BeginRead call so that the buffer contained all the data after all BeginRead calls had completed.

I find this very confusing. Am I missing something? I'd be interested to read comments on this.

Thanks.
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,410
Location
Norway
Programming Experience
10+
Call BeginRead and supply a byte array buffer, EndRead returns when the requested read is completed and return value tell how many bytes were filled into the buffer. You need access to the buffer when starting a read and when read completes, for example you can have variable in class that hold this, or a class to hold state info for this purpose.
 

hopeful

Member
Joined
Jun 25, 2009
Messages
7
Location
New Zealand
Programming Experience
10+
Call BeginRead and supply a byte array buffer, EndRead returns when the requested read is completed and return value tell how many bytes were filled into the buffer. You need access to the buffer when starting a read and when read completes, for example you can have variable in class that hold this, or a class to hold state info for this purpose.
Thanks, I understand this but my questions specifically relate to the behaviour of BeginRead when there are multiple calls to BeginRead within the call back function.

Here is the Microsoft code sample that I am referring to:

Code:
Public Shared Sub myReadCallBack(ar As IAsyncResult)

   Dim myNetworkStream As NetworkStream = CType(ar.AsyncState, NetworkStream)
   Dim myReadBuffer(1024) As Byte
   Dim myCompleteMessage As [String] = ""
   Dim numberOfBytesRead As Integer

   numberOfBytesRead = myNetworkStream.EndRead(ar)
   myCompleteMessage = [String].Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead))

   ' message received may be larger than buffer size so loop through until you have it all.
   While myNetworkStream.DataAvailable

      myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length, New AsyncCallback(AddressOf NetworkStream_ASync_Send_Receive.myReadCallBack), myNetworkStream)
   End While


   ' Print out the received message to the console.
   Console.WriteLine(("You received the following message : " + myCompleteMessage))
End Sub 'myReadCallBack
My questions are detailed in points 1,2,3 and 4 in my original post. Any comments you have on these would be appreciated.
 

hopeful

Member
Joined
Jun 25, 2009
Messages
7
Location
New Zealand
Programming Experience
10+
For anyone that is interested I have found some of the answers to my questions.

The 3.5 version of the EndRead documentation contains a user annotation that confirms the code sample is quite wrong.

Not only is the code using the local buffer before the buffer contains any data, but it wouldn't work anyway because the call back function needs to access the same buffer that was passed to the BeginRead that invoked the call back. Therefore the buffer passed to the original BeginRead either needs to be directly accessible to the call back function or passed through in the state object.

Apparently there is also a problem with the use of the DataAvailable property and I also found a comment somewhere that the threading of the call back function is not exactly as described in the documentation.

Anyway it is becoming clearer to me but any additional comments would be appreciated.

Thanks
 
Last edited:
Top Bottom