473,320 Members | 1,916 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Asynchronously reading off a TcpSocket the best way

I have an application that does lots of socket communications all asynchronously via the TcpClient class.

The code has been working 99.9999% of the time (yeah one of those bugs) but occasionally the receiving thread would get 'stuck'.

The pattern that I have used from the reading is quite common...

AutoResetEvent waitForReadToComplete;
NetworkStream stream;

.... code to start the socket, send some data and then read the data by calling...

private void ReceiveDataOfTheSocket()
{
try
{

// Convert the request into a byte array
waitForReadToComplete = new AutoResetEvent(false);

IAsyncResult ar = stream.BeginRead(receiveBytes, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), stream);

// Wait for the receive to complete...
waitForReadToComplete.WaitOne();

...

}
catch(Exception exp)
{
.. does something meaningful
}

}

private void ReadAsync(IAsyncResult ar)
{
try
{
... read data off the socket

if (amountOfDataReadOfTheSocket > 0)
{
// Recall this routine
streamAsync.BeginRead(receiveBytes, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), streamAsync);

}
else
{
waitForReadToComplete.Set();
}

}
catch(Exception exp)
{
.. do some stuff and then..
waitForReadToComplete.Set();
}
}

After maybe a day or two of running successfully the application would appear to be stopped. In the debugger I was able to see that one thread was stopped at waitForReadToComplete.WaitOne(); in the ReceiveData() function yet there was no other thread running in ReadAsync(). There were other threads in the application but they were not affecting this code and were working as expected. Thread starvation was not an issue.

It was as if .BeginRead() had been called successfully but either ReadAsync() had either not been run or it had run and somehow waitForReadToComplete.Set(); had not been called despite the exception handler.

I took a bit of a guess and thought that BeginRead() had somehow failed yet no exception had been thrown.

I changed the line...

waitForReadToComplete.WaitOne();

to

while ((waitForReadToComplete.WaitOne(5000, true) == false) && (ar.IsCompleted == false))
{
// Do nothing
}

....which effectively waits for the asyncread to complete or the ar.IsCompleted to be set to true - whatever comes first.

The program has now been running for days without a problem.

I am not one to say "lets not worry about it since it is working". I want to know why this as.IsCompleted is required when waitforReadToComplete.WaitOne() should be more than sufficient.

This program is following the HTTP protocol. The only thing that I can think of is that the HTTP send has worked and then the .BeginRead() is called. At this moment the socket is connected so no exception is thrown. However, it is then closed in the moments thereafter and ReadAsync() is therefore never called. The only indication is that ar.IsCompleted is set to true.

Another idea that I have is that the MSDN help suggests that the code in ReadAsync() that re-sets up the async read should be...

// 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(ReadAsync),
myNetworkStream);

}
Maybe if I did that then it would work better. ...but I can't see this as being very good code. It is saying that in the place where data is received off the socket, repeatedly asynchronously re-read off the socket and make a callback to this routhine until you have read all of the data. Surely the "while(myNetworkStream.DataAvailable){" is totally redundant and possibly quite foolish?

Is there a better way to code this? Does anyone have any better ideas about what maybe causing it or how to check for it? So many questions.

Thanks in advance.

Dave A



Jan 28 '06 #1
5 9517
Where are you calling stream.EndRead(...)?

streamAsync.BeginRead(...) in the ReadAsync(...) method returns value, why
there should be exception.
You can add finally {} block

The code you've posted can be replaced with the synchronous equivalent
without no loss to performance.
Let me explain why.

After you issue stream.BeginRead(...) in the ReceiveDataOfTheSocket(), you
start waiting on the event, that will signal the end of receive, right?

So, ReceiveDataOfTheSocket would block until data is read. If that is the
behavior you expect - it is far more simpler to call stream.Read(...) until
no data will be available on the srtream.
This approach will is free of deadlocks and threading issues.

--
Vadym Stetsyak aka Vadmyst
http://vadmyst.blogspot.com

"Dave A" <da**@sigmasolutionsdonotspamme.com.au> wrote in message
news:e1**************@TK2MSFTNGP15.phx.gbl...
I have an application that does lots of socket communications all
asynchronously via the TcpClient class.

The code has been working 99.9999% of the time (yeah one of those bugs) but
occasionally the receiving thread would get 'stuck'.

The pattern that I have used from the reading is quite common...

AutoResetEvent waitForReadToComplete;
NetworkStream stream;

.... code to start the socket, send some data and then read the data by
calling...

private void ReceiveDataOfTheSocket()
{
try
{

// Convert the request into a byte array
waitForReadToComplete = new AutoResetEvent(false);

IAsyncResult ar = stream.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), stream);

// Wait for the receive to complete...
waitForReadToComplete.WaitOne();

...

}
catch(Exception exp)
{
.. does something meaningful
}

}

private void ReadAsync(IAsyncResult ar)
{
try
{
... read data off the socket

if (amountOfDataReadOfTheSocket > 0)
{
// Recall this routine
streamAsync.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), streamAsync);

}
else
{
waitForReadToComplete.Set();
}

}
catch(Exception exp)
{
.. do some stuff and then..
waitForReadToComplete.Set();
}
}

After maybe a day or two of running successfully the application would
appear to be stopped. In the debugger I was able to see that one thread was
stopped at waitForReadToComplete.WaitOne(); in the ReceiveData() function
yet there was no other thread running in ReadAsync(). There were other
threads in the application but they were not affecting this code and were
working as expected. Thread starvation was not an issue.

It was as if .BeginRead() had been called successfully but either
ReadAsync() had either not been run or it had run and somehow
waitForReadToComplete.Set(); had not been called despite the exception
handler.

I took a bit of a guess and thought that BeginRead() had somehow failed yet
no exception had been thrown.

I changed the line...

waitForReadToComplete.WaitOne();

to

while ((waitForReadToComplete.WaitOne(5000, true) == false) &&
(ar.IsCompleted == false))
{
// Do nothing
}

....which effectively waits for the asyncread to complete or the
ar.IsCompleted to be set to true - whatever comes first.

The program has now been running for days without a problem.

I am not one to say "lets not worry about it since it is working". I want
to know why this as.IsCompleted is required when
waitforReadToComplete.WaitOne() should be more than sufficient.

This program is following the HTTP protocol. The only thing that I can
think of is that the HTTP send has worked and then the .BeginRead() is
called. At this moment the socket is connected so no exception is thrown.
However, it is then closed in the moments thereafter and ReadAsync() is
therefore never called. The only indication is that ar.IsCompleted is set
to true.

Another idea that I have is that the MSDN help suggests that the code in
ReadAsync() that re-sets up the async read should be...

// 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(ReadAsync),
myNetworkStream);

}
Maybe if I did that then it would work better. ...but I can't see this as
being very good code. It is saying that in the place where data is received
off the socket, repeatedly asynchronously re-read off the socket and make a
callback to this routhine until you have read all of the data. Surely the
"while(myNetworkStream.DataAvailable){" is totally redundant and possibly
quite foolish?

Is there a better way to code this? Does anyone have any better ideas about
what maybe causing it or how to check for it? So many questions.

Thanks in advance.

Dave A


Jan 28 '06 #2
Vadym,

The code posted was abbreviated somewhat for the sake of brevity.

I am calling "stream.EndRead(...)" as part of the note " ... read data off
the socket" in the function ReadAsync(). The details of this code are
irrelevant to the conversation at hand and were omitted to highlight the
important aspects.

It was written asynchronously since I require this function to exhibit an
optional timeout behaviour. Again it was not explicitly described in the
example code. When a timeout is specified I pass this timeout into the
WaitOne() function. If I were to have implemented a synchronous mode of
operation as you suggested than an extra thread would need to automatically
close the socket if the timeout expires. This pattern is not as elegant as
the one described in my code.

Having said all of that everyone of my original questions remain.

Regards
Dave A
"Vadym Stetsyak" <va*****@ukr.net> wrote in message
news:eq**************@TK2MSFTNGP12.phx.gbl...
Where are you calling stream.EndRead(...)?

streamAsync.BeginRead(...) in the ReadAsync(...) method returns value, why
there should be exception.
You can add finally {} block

The code you've posted can be replaced with the synchronous equivalent
without no loss to performance.
Let me explain why.

After you issue stream.BeginRead(...) in the ReceiveDataOfTheSocket(),
you start waiting on the event, that will signal the end of receive,
right?

So, ReceiveDataOfTheSocket would block until data is read. If that is the
behavior you expect - it is far more simpler to call stream.Read(...)
until no data will be available on the srtream.
This approach will is free of deadlocks and threading issues.

--
Vadym Stetsyak aka Vadmyst
http://vadmyst.blogspot.com

"Dave A" <da**@sigmasolutionsdonotspamme.com.au> wrote in message
news:e1**************@TK2MSFTNGP15.phx.gbl...
I have an application that does lots of socket communications all
asynchronously via the TcpClient class.

The code has been working 99.9999% of the time (yeah one of those bugs)
but occasionally the receiving thread would get 'stuck'.

The pattern that I have used from the reading is quite common...

AutoResetEvent waitForReadToComplete;
NetworkStream stream;

... code to start the socket, send some data and then read the data by
calling...

private void ReceiveDataOfTheSocket()
{
try
{

// Convert the request into a byte array
waitForReadToComplete = new AutoResetEvent(false);

IAsyncResult ar = stream.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), stream);

// Wait for the receive to complete...
waitForReadToComplete.WaitOne();

...

}
catch(Exception exp)
{
.. does something meaningful
}

}

private void ReadAsync(IAsyncResult ar)
{
try
{
... read data off the socket

if (amountOfDataReadOfTheSocket > 0)
{
// Recall this routine
streamAsync.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), streamAsync);

}
else
{
waitForReadToComplete.Set();
}

}
catch(Exception exp)
{
.. do some stuff and then..
waitForReadToComplete.Set();
}
}

After maybe a day or two of running successfully the application would
appear to be stopped. In the debugger I was able to see that one thread
was stopped at waitForReadToComplete.WaitOne(); in the ReceiveData()
function yet there was no other thread running in ReadAsync(). There were
other threads in the application but they were not affecting this code and
were working as expected. Thread starvation was not an issue.

It was as if .BeginRead() had been called successfully but either
ReadAsync() had either not been run or it had run and somehow
waitForReadToComplete.Set(); had not been called despite the exception
handler.

I took a bit of a guess and thought that BeginRead() had somehow failed
yet no exception had been thrown.

I changed the line...

waitForReadToComplete.WaitOne();

to

while ((waitForReadToComplete.WaitOne(5000, true) == false) &&
(ar.IsCompleted == false))
{
// Do nothing
}

...which effectively waits for the asyncread to complete or the
ar.IsCompleted to be set to true - whatever comes first.

The program has now been running for days without a problem.

I am not one to say "lets not worry about it since it is working". I want
to know why this as.IsCompleted is required when
waitforReadToComplete.WaitOne() should be more than sufficient.

This program is following the HTTP protocol. The only thing that I can
think of is that the HTTP send has worked and then the .BeginRead() is
called. At this moment the socket is connected so no exception is thrown.
However, it is then closed in the moments thereafter and ReadAsync() is
therefore never called. The only indication is that ar.IsCompleted is set
to true.

Another idea that I have is that the MSDN help suggests that the code in
ReadAsync() that re-sets up the async read should be...

// 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(ReadAsync),
myNetworkStream);

}
Maybe if I did that then it would work better. ...but I can't see this as
being very good code. It is saying that in the place where data is
received off the socket, repeatedly asynchronously re-read off the socket
and make a callback to this routhine until you have read all of the data.
Surely the "while(myNetworkStream.DataAvailable){" is totally redundant
and possibly quite foolish?

Is there a better way to code this? Does anyone have any better ideas
about what maybe causing it or how to check for it? So many questions.

Thanks in advance.

Dave A



Jan 29 '06 #3
One of the reasons why the call to BeginRead(...) hasn't ended up with
exception is that operation was scheduled for completion.
When you call on BeginRead in Network stream BeginReceive(...) of the
underlying socket is called. After that unmanaged WSARecv func is called.
This func can return either 0 or SOCKET_ERROR with underlying "I/O pending"
error. In this case BeginRead/BeginReceive will not return exception.

So, to handle this correctly you can either check IsCompleted of
IAsyncResult or DataAvailable property of the NetworkStream

About the way how to improve the code: instead of
while ((waitForReadToComplete.WaitOne(5000, true) == false) &&
(ar.IsCompleted == false))
{
// Do nothing
}

you can use ar.AsyncWaitHandle.WaitOne(5000, true), it is more elegant and
you do not need additional wait object ( waitForReadToComplete ).

private void ReceiveDataOfTheSocket()
{
try
{
// Convert the request into a byte array
IAsyncResult ar = stream.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), stream);

// Wait for the receive to complete...
ar.AsyncWaitHandle.WaitOne(5000, true),
...
}
catch(Exception exp)
{
.. does something meaningful
}
}

--
Vadym Stetsyak aka Vadmyst
http://vadmyst.blogspot.com

"Dave A" <da**@sigmasolutionsdonotspamme.com.au> wrote in message
news:%2****************@TK2MSFTNGP10.phx.gbl...
Vadym,

The code posted was abbreviated somewhat for the sake of brevity.

I am calling "stream.EndRead(...)" as part of the note " ... read data off
the socket" in the function ReadAsync(). The details of this code are
irrelevant to the conversation at hand and were omitted to highlight the
important aspects.

It was written asynchronously since I require this function to exhibit an
optional timeout behaviour. Again it was not explicitly described in the
example code. When a timeout is specified I pass this timeout into the
WaitOne() function. If I were to have implemented a synchronous mode of
operation as you suggested than an extra thread would need to
automatically close the socket if the timeout expires. This pattern is
not as elegant as the one described in my code.

Having said all of that everyone of my original questions remain.

Regards
Dave A

Jan 29 '06 #4
I agree with you.

If we are right then the MSDN help at
http://msdn2.microsoft.com/system.ne...beginread.aspx
in the context of reading data off a socket is probably incorrect. It
simply does the .WaitOne() (and on its own WaitHandle instead of the
ar.AsyncWaitHandle)

So is the Help wrong? and what do we need to do get it fixed?

Dave A

"Vadym Stetsyak" <va*****@ukr.net> wrote in message
news:%2***************@TK2MSFTNGP12.phx.gbl...
One of the reasons why the call to BeginRead(...) hasn't ended up with
exception is that operation was scheduled for completion.
When you call on BeginRead in Network stream BeginReceive(...) of the
underlying socket is called. After that unmanaged WSARecv func is called.
This func can return either 0 or SOCKET_ERROR with underlying "I/O
pending" error. In this case BeginRead/BeginReceive will not return
exception.

So, to handle this correctly you can either check IsCompleted of
IAsyncResult or DataAvailable property of the NetworkStream

About the way how to improve the code: instead of
while ((waitForReadToComplete.WaitOne(5000, true) == false) &&
(ar.IsCompleted == false))
{
// Do nothing
}

you can use ar.AsyncWaitHandle.WaitOne(5000, true), it is more elegant and
you do not need additional wait object ( waitForReadToComplete ).

private void ReceiveDataOfTheSocket()
{
try
{
// Convert the request into a byte array
IAsyncResult ar = stream.BeginRead(receiveBytes, 0,
tcpClient.ReceiveBufferSize, new AsyncCallback(ReadAsync), stream);

// Wait for the receive to complete...
ar.AsyncWaitHandle.WaitOne(5000, true),
...
}
catch(Exception exp)
{
.. does something meaningful
}
}

--
Vadym Stetsyak aka Vadmyst
http://vadmyst.blogspot.com

"Dave A" <da**@sigmasolutionsdonotspamme.com.au> wrote in message
news:%2****************@TK2MSFTNGP10.phx.gbl...
Vadym,

The code posted was abbreviated somewhat for the sake of brevity.

I am calling "stream.EndRead(...)" as part of the note " ... read data
off the socket" in the function ReadAsync(). The details of this code are
irrelevant to the conversation at hand and were omitted to highlight the
important aspects.

It was written asynchronously since I require this function to exhibit an
optional timeout behaviour. Again it was not explicitly described in the
example code. When a timeout is specified I pass this timeout into the
WaitOne() function. If I were to have implemented a synchronous mode of
operation as you suggested than an extra thread would need to
automatically close the socket if the timeout expires. This pattern is
not as elegant as the one described in my code.

Having said all of that everyone of my original questions remain.

Regards
Dave A


Jan 29 '06 #5
Another MS doc says that
"The return value allows the client to wait for an asynchronous operation to
complete instead of polling IsCompleted until the operation concludes. The
return value can be used to perform a WaitOne, WaitAny, or WaitAll
operation."

(
http://msdn.microsoft.com/library/de...andleTopic.asp )

So, the best way will be to make code change and test :8-)

--
Vadym Stetsyak aka Vadmyst
http://vadmyst.blogspot.com
Jan 30 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: DaveC | last post by:
Hello, I'm loading a rather large xml document from a remote server, but this stalls my app? how can I load it Asynchronously, the XmlDocument class has no .async property? Also I would like to...
4
by: Vish | last post by:
Hi, I am having a problem with my form being too slow to load up. I have a 4-5 of comboboxes on the form that load a lot (~30,000 records) into them. So this is causing a lot delay (5-6 seconds)...
0
by: archana | last post by:
Hi all, I am having problem in one web method which i am running asynchronously I set oneway attribute in web method. What i want is once client called this web method this should start...
3
by: Sidanalism | last post by:
I miss the old way when asynchronous calls are driven my window messages. Yes a thread pool might greatly improve application performance but there are time I don't want my event to be fire in a...
14
by: Mike C# | last post by:
Hi all, Is it possible to make 10 POST requests from ASP.NET asynchronously? I have been working on this problem for a few days now, and I seem to keep running up against IIS limitations. ...
4
by: GR | last post by:
Hi, I've got a soap message as a string and would like to post it to a webservice (in C#) asynchronously: For example something like: string soap = "<soap:Envelope...
6
by: Samuel | last post by:
I need an open source socket components library like Delphi's ClientSocket and ServerSocket,who can tell me?if not found, give me some other suggestion(simple is best, i only need tcp).
9
by: Denis | last post by:
Hello, Maybe somebody already solved this task. I need to load JS asynchronously without blocking browser. This means that I do not need to block browser to load/render during loading script. The...
2
by: Kerem Gümrükcü | last post by:
Hi, i have a (simple) dynamic plugin architecture and i want to call a member function from the dynamically loaded assembly and its instanciated class. The Code looks like this: foreach...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.