When does a Stream EndRead Block the Callback - c#

I am relatively new to using the Async pattern for stream reading and writing, and wondered if the answer to this question is so obvious it is not written anywhere explicitly:
When calling a NetworkStream.BeginRead, I pass a callback parameter, which according to MSDN is executed "when BeginRead completes". It also says that "your callback method should call the EndRead method."
Then according to the documentation for NetworkStream.EndRead, the "method completes the asynchronous read operation started in the BeginRead method." It also mentions that this method "blocks until data is available."
I know the EndRead method is also useful for determining the number of bytes received.
My question is:
If the EndRead method is called within the BeginRead callback, does it ever really block? Isn't the read operation already complete when the callback is invoked?
Sample Code
byte[] streamBuffer = new byte[1024];
public void SomeFunction()
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Parse("127.0.0.1"), 32000);
NetworkStream stream = client.GetStream();
stream.BeginRead(streamBuffer,0,streamBuffer.Length,ReadCallback,stream);
}
public void ReadCallback(IAsyncResult ar)
{
NetworkStream stream = ar.AsyncState as NetworkStream;
// Will this call ever actually "block" or will it
// return immediately? Isn't the read operation
// already complete?
int bytesRead = stream.EndRead(ar);
// Other stuff here
}

The read operation is always completed when the callback fires. Completion is what gets the callback fired in the first place. So EndRead() will never block when it is used in the callback method.
Do note that "completed" can also mean "failed", EndRead() will throw the exception. A very common exception is ObjectDisposedException, thrown when the socket is closed while an asynchronous read is in progress. Typical when you exit your program, be sure to catch it.

You can use EndRead in two situations:
You can use EndRead in your call back functions. At this point nothing will be blocked.
You can also use EndRead without the call back function:
myStream.BeginRead(...);
// Do a lot of work at the same time.
// When my work is done, wait for the stream to finish its work.
myStream.EndRead(...);
EndRead should always be called to report some errors have occured. If an error has occured, an EndRead will throw an exception.

No, because the EndRead method is being called (and blocking) within the delegate which is being called asynchronously. So yes, the method with EndRead is blocking, but not on the thread of execution that called BeginRead.

Related

Callback method indirectly calling back itself

In a C# class, the following format is used for reading data from a socket asynchronously.
As you can see in the code, it uses AsyncReceive to read data from a socket. It calls back OnDataReception when data is received.
In OnDataReception, received data is processed and again calls ListenForData if the conversation is not finished yet.
Does this code snippet create any kind of indefinite recursion? (functions or threads)
class ClientConnection{
Socket socket = ...
SocketAsyncEventArgs args = ...
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnDataReception);
...
public void ListenForData(){
...
socket.ReceiveAsync(args);
...
}
public void OnDataReception(Object obj, SocketAsyncEventArgs args){
...
// if conversation is finished, return
// else call ListenForData() again...
}
...
}
First I like to mention, that the question is similar to How does this not cause a stack overflow?.
Now to be specific on your questions: The amount of threads used by the code snippet is constrained by the number of threads available in the thread pool used to execute ReceiveAsync. New threads are just produced, if a previous call to the async method returned.
Further OnDataReception does call ListenForData every time. ListenForData instead does not directly call OnDataReception. This means, there is no direct functional recursion between the two methods. ReceiveAsync executed in a background-thread does not produce nested stack-frames.
So in my opinion there are no hidden recursions in the code.
Per MSDN Documentation on Socket.ReceiveAsync:
Returns true if the I/O operation is pending. The
SocketAsyncEventArgs.Completed event on the e parameter will be raised
upon completion of the operation.
Returns false if the I/O operation
completed synchronously. In this case, The
SocketAsyncEventArgs.Completed event on the e parameter will not be
raised and the e object passed as a parameter may be examined
immediately after the method call returns to retrieve the result of
the operation.
To answer your question, no it will not create an infinite loop/recursion.
Your ListenForData method will only call OnDataReception once per call to ReceiveAsync. Since you are calling ListenForData in OnDataReception and not in a loop, it will look like this:
ListenForData called!
(time elapses)
OnDataReception called!
ListenForData called!
(time elapses)
OnDataReception called!
ListenForData called!
...
This is almost identical to using Socket.BeginReceive, passing an AsyncCallback and then calling Socket.EndReceive followed by another Socket.BeginReceive in the callback. It's an indefinite loop but not an infinite one.
See:
void StartReceiving()
{
// Start receiving asynchronously...
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, OnDataReceived, null);
}
void OnDataReceived(IAsyncResult result)
{
// Finish receiving this data.
var numberOfBytesReceived = socket.EndReceive(result);
// Start receiving asynchronously again...
if(numberOfBytesReceived > 0 && socket.Connected)
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, OnDataReceived, null);
}
This would not produce any indefinite recursion, but you can change the architecture slightly for the effective resource utilization.
You could use two different threads for listening and the conversion, since the program need to listen the port irrespective of the conversion result.

Understanding ManualResetEvent in asynchronous server socket

Socket SocketSrv;
public static ManualResetEvent Done = new ManualResetEvent(false);
IPEndPoint IPP = new IPEndPoint(IPAddress.Any, 1234);
void Listening()
{
SocketSrv = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
SocketSrv.Bind(IPP);
SocketSrv.Listen(5);
while (true)
{
Done.Reset();
info.Text = "Waiting for connections....";
SocketSrv.BeginAccept(new AsyncCallback(Connection),
SocketSrv);
Done.WaitOne();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
void Connection(IAsyncResult ar)
{
Done.Set();
Socket con= (Socket)ar.AsyncState;
Socket handler = con.EndAccept(ar);
}
I'm trying to understand the ManualResetEvent in this asynchronus operation since I've never used it.
Step1. The SocketSrv is created to accept TCP connections and the type of sending and receving "commands" is stream.
Step2. The socket is binded with the ip,port and then we start listening for connections.
Step3. In the while loop :
The ManualResetEvent is Reset (I understand that the ManualResetEvent is a class which type is Boolean and indicates whenever a thread is busy or not).In this case , the event is always reset because if there's a connection made and another one is coming I need to reset it and start the "operation" again.
In the BeingAccept I'm being starting the asynchronous operation, the callback function which is executed and the IAsyncResult argument which will become the "socket".
Step4. The ResetEvent is now Waiting blocking the current thread and waiting for the handler in the connection method to be ended so it can finish initializing the current connection.
Step5. In the connection thread the ResetEvent sets the signal true which means... well I don't know what does it means. I think it tells to the ResetEvent to unblock the main thread.
In the 'con' socket I'm getting the AsyncState. I have no idea what does it means.
In the handler socket I'm telling the ResetEvent that the connection was made.
Things being said, could someone tell me if what I've said is true/wrong and why?
The event is used so that when a connection occurs BeginAccept won't be called again until the Connect method has been invoked. e.g. WaitOne halts the thread until Set is called. Reset is called to set the state of the event back to signalled so that WaitOne will halt the thread again so that it will wait for Connect to be called again.
Personally, I don't use this particular pattern. I've never seen an explanation of the point of this pattern. If there were some shared state between the BeginAccept loop and the Connect method, it might make sense. But, as written no state is guarded by use of the event. When I use BeginAccept I simply don't use an event, and I've used code like this to deal with many connections a second. Use of the event will do nothing to prevent errors with too many connections at a time. And quite frankly, to use an asynchronous method and force it to effectively be synchronous defeats the purpose.
The AysncState, from the point of view of BeginAccept, is simply opaque data. It's the "state" that is used for that particular async operation. This "state" is application-specific. You use whatever you need when you want to process a connection asynchronously. In the case of the BeginAccept callback, you usually want to do something with the server socket and it's passed in for the state so you have access to it to call EndAccept. Since SocketSrv is a member field, you don't really need to do this, you could do this instead:
SocketSrv.BeginAccept(new AsyncCallback(Connection), null);
//...
void Connection(IAsyncResult ar)
{
Socket handler = SocketSrv.EndAccept(ar);
//...
}
Your comments seem to suggest you have a good grasp of this particular bit of code. Your "Step4" is a bit off, it's not waiting for the Connection method to end, just for it to start (since Set is called as the first line). And yes, "Step5", the Set means it unblocks the WaitOne so the main thread call call Reset then BeginAccept.

Delegates dispatched by dispatcher are never fired

I am trying to fire a method as a result to an asynchronous read operation on a NetworkStream. The read operation is done via BeginRead and EndRead, resulting in the EndRead being called in the callback specified with BeginRead. All pretty basic stuff. Now, as the callback is done in a system generated Thread, the data read from the NetworkStream is no longer owned by my thread, that called the BeginRead. To overcome that, I wrote a method to further process the data read, which I try to call via my Thread's dispatcher.
// These are created in my Thread
private delegate void ReceiverCallback(IPEndPoint sender, byte[] data);
private Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
With the callback looking like this:
private void DataReceived(IAsyncResult result)
{
DataReceivedStruct drs = (DataReceivedStruct)result.AsyncState;
NetworkStream used = drs.stream;
AutoResetEvent handle = drs.waitHandle;
used.EndRead(result);
DispatchRaiseReceived(readBuffer);
handle.Set();
}
The DataReceivedStruct is a simple struct holding the NetworkStream and an AutoResetEvent.
ReadBuffer is a global private byte[] of 1024 length, as BeginRead and EndRead aren't called in the same method.
The DispatchRaiseReceive method looks like this:
private void DispatchRaiseReceived(byte[] data)
{
dispatcher.BeginInvoke((ReceiverCallback)RaiseReceived, socket.Client.RemoteEndPoint, data);
}
Where socket is a TcpClient object.
The disptached method looks like the following bit of code. What this does is simply pass the data along via an event for further processing.
private void RaiseReceived(IPEndPoint sender, byte[] data)
{
if(IsEnabled){
if (Received != null)
{
Received(this, new TCPDataArgs(sender, data));
}
}
}
The actual method that the dispatcher needs to call, is never called. Now from what I've been able to find on the web is that it could have something to do with the dispatcher not being created on the correct Thread, and thus it is never invoking the method on the correct Thread. However, the dispatcher is created on my Thread, so that shouldn't apply.
As an attempt to fix this, I explicitly got the Dispatcher from my UI-Thread, and passed that along to the desired place I wanted to use it. This instead of trying to get it with Dispatcher.CurrentDispatcher. And what do you know, it worked. The delegate is now being called correctly.
Apparently Dispatcher.CurrentDispatcher didn't get the correct Dispatcher I wanted it to use.

Calling BeginRead from a NetworkStream

Ok I want to connect to a Socket and read a network stream using the System.Net.Sockets.NetworkStream class. This is what I have so far:
NetworkStream myNetworkStream;
Socket socket;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw,
ProtocolType.IPv4);
socket.Connect(IPAddress.Parse("8.8.8.8"), 8888);
myNetworkStream = new NetworkStream(socket);
byte[] buffer = new byte[1024];
int offset = 0;
int count = 1024;
myNetworkStream.BeginRead(buffer, offset, count, ??, ??);
Now I need an AsyncCallback and an Object state to complete my BeginRead method but I'm not even sure if this is going to work. I'm a bit lost at this point! Where do I need to go from here?
Basically, when you call the Begin* method on an asynchronous operation, there needs to be a call to a corresponding End* statement (for more detailed information, see the Asynchronous Programming Overview on MSDN, specifically the section titled "Ending an Asynchronous Operation").
That said, you generally want to pass a method/anonymous method/lambda expression which will do one or two things:
1) Call the corresponding End* method, in this case, Stream.EndRead. This call will not block when called because the callback will not be called until the operation is complete (note that if an exception occurred during the async call then this exception will be thrown when the End* method is called).
2) Possibly start a new asynchronous call. In this case, it's assumed you'll want to read more data, so you should start a new call to Stream.BeginRead
Assuming you want to do #2, you can do the following:
// Declare the callback. Need to do that so that
// the closure captures it.
AsyncCallback callback = null;
// Assign the callback.
callback = ar => {
// Call EndRead.
int bytesRead = myNetworkStream.EndRead(ar);
// Process the bytes here.
// Determine if you want to read again. If not, return.
if (!notMoreToRead) return;
// Read again. This callback will be called again.
myNetworkStream.BeginRead(buffer, offset, count, callback, null);
};
// Trigger the initial read.
myNetworkStream.BeginRead(buffer, offset, count, callback, null);
However, if you are using .NET 4.0, this becomes much easier using the FromAsync method on the TaskFactory class.

Difference between NetworkStream.Read() and NetworkStream.BeginRead()?

I need to read from NetworkStream which would send data randomly and the size of data packets also keep varying. I am implementing a multi-threaded application where each thread would have its own stream to read from. If there is no data on the stream, the application should keep waiting for the data to arrive. However, if the server is done sending data and has terminated the session, then it should exit out.
Initially I had utilised the Read method to obtain the data from the stream, but it used to block the thread and kept waiting until data appeared on the stream.
The documentation on MSDN suggests,
If no data is available for reading,
the Read method returns 0. If the
remote host shuts down the connection,
and all available data has been
received, the Read method completes
immediately and return zero bytes.
But in my case, I have never got the Read method to return 0 and exit gracefully. It just waits indefinitely.
In my further investigation, I came across BeginRead which watches the stream and invokes a callback method asynchronously, as soon as it receives the data. I have tried to look for various implementations using this approach as well, however, I was unable to identify when would using BeginRead be beneficial as opposed to Read.
As I look at it, BeginRead has just the advantage of having the async call, which would not block the current thread. But in my application, I already have a separate thread to read and process the data from stream, so that wouldn't make much difference for me.
Can anyone please help me understand the Wait and Exit mechanism for
BeginRead and how is it different from Read?
What would be the best way to implement the desired functionality?
I use BeginRead, but continue blocking the thread using a WaitHandle:
byte[] readBuffer = new byte[32];
var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length,
null, null);
WaitHandle handle = asyncReader.AsyncWaitHandle;
// Give the reader 2seconds to respond with a value
bool completed = handle.WaitOne(2000, false);
if (completed)
{
int bytesRead = stream.EndRead(asyncReader);
StringBuilder message = new StringBuilder();
message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead));
}
Basically it allows a timeout of the async reads using the WaitHandle and gives you a boolean value (completed) if the read was completed in the set time (2000 in this case).
Here's my full stream reading code copied and pasted from one of my Windows Mobile projects:
private static bool GetResponse(NetworkStream stream, out string response)
{
byte[] readBuffer = new byte[32];
var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length, null, null);
WaitHandle handle = asyncReader.AsyncWaitHandle;
// Give the reader 2seconds to respond with a value
bool completed = handle.WaitOne(2000, false);
if (completed)
{
int bytesRead = stream.EndRead(asyncReader);
StringBuilder message = new StringBuilder();
message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead));
if (bytesRead == readBuffer.Length)
{
// There's possibly more than 32 bytes to read, so get the next
// section of the response
string continuedResponse;
if (GetResponse(stream, out continuedResponse))
{
message.Append(continuedResponse);
}
}
response = message.ToString();
return true;
}
else
{
int bytesRead = stream.EndRead(asyncReader);
if (bytesRead == 0)
{
// 0 bytes were returned, so the read has finished
response = string.Empty;
return true;
}
else
{
throw new TimeoutException(
"The device failed to read in an appropriate amount of time.");
}
}
}
Async I/O can be used to achieve the same amount of I/O in less threads.
As you note, right now your app has one thread per Stream. This is OK with small numbers of connections, but what if you need to support 10000 at once? With async I/O, this is no longer necessary because the read completion callback allows context to be passed identifying the relevant stream. Your reads no longer block, so you don't need one thread per Stream.
Whether you use sync or async I/O, there is a way to detect and handle stream closedown on the relevant API return codes. BeginRead should fail with IOException if the socket has already been closed. A closedown while your async read is pending will trigger a callback, and EndRead will then tell you the state of play.
When your application calls BeginRead,
the system will wait until data is
received or an error occurs, and then
the system will use a separate thread
to execute the specified callback
method, and blocks on EndRead until
the provided NetworkStream reads data
or throws an exception.
Did you try server.ReceiveTimeout? You can set the time which Read() functon will wait for incomming data before returning zero. In your case, this property is probably set to infinite somewhere.
BeginRead is an async process which means your main thread will start execute Read in another process. So now we have 2 parallel processes. if u want to get the result, u have to call EndRead, which will gives the result.
some psudo
BeginRead()
//...do something in main object while result is fetching in another thread
var result = EndRead();
but if your main thread doesn't have anything else to do and u have to need the result, u should call Read.

Categories

Resources