CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Stephen Brooker » Mon, 04 Oct 2004 14:48:58 GMT

Hi all,

I've got a basic TCP app that is giving me trouble. I have a separate
class that takes care of the TCP connection, and uses the NetworkStreams
BeginRead and EndRead with a callback function to deal with the server
response. All works well and the data is received OK. Once all the data
is received, the connection is closed and I fire an event indicating all
is finished. The event is handled in the main form of the application
and I can work with the returned data OK.

The problem arises when I try to add some of the data to a TreeView. It
complains that only the creating thread can modify the TreeViews data
and I should use BeginInvoke etc (all this so far I understand). So I
assume control is still with the thread created by BeginRead? Am I
correct? If so, is there any way of forcing control to return to the
main forms threads once the event is fired for the data being received?
I've been able to set values on several other controls, the TreeView is
the only one giving me problems (why is it so picky when none of the
other controls are).

TIA

Steve.

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Jon Skeet [C# MVP] » Mon, 04 Oct 2004 15:45:41 GMT



The thread the event handler gets called on will be whatever thread
raises the event - probably a threadpool thread, yes. (BeginRead
doesn't necessarily "create" a thread though, and there's no guarantee
that all the data will be read by one thread - usually you call
BeginRead multiple times until all the data has been read, and the
callbacks for those calls could each happen on a different thread.)


By using BeginInvoke (or Invoke) exactly as it says you should.


You've been lucky, that's all. The golden rule of Windows Forms
threading is that you don't do *anything* with a control apart from
BeginInvoke, EndInvoke, Invoke, InvokeRequired, or CreateGraphics,
unless you're running on the thread which created the control.

See http://www.pobox.com/ ~skeet/csharp/threads/winforms.shtml

--
Jon Skeet - < XXXX@XXXXX.COM >
http://www.pobox.com/ ~skeet
If replying to the group, please do not mail me too

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Stephen Brooker » Mon, 04 Oct 2004 18:35:38 GMT

>

OK, thanks Jon.

So does that effectively mean that every function in the main form that
modifies the GUI, and gets called after the TCP connection is
established needs modification using Invoke etc?

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Jon Skeet [C# MVP] » Mon, 04 Oct 2004 18:42:16 GMT


If it's still in a thread other than the UI thread, yes.

--
Jon Skeet - < XXXX@XXXXX.COM >
http://www.pobox.com/ ~skeet
If replying to the group, please do not mail me too

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Stephen Brooker » Mon, 04 Oct 2004 19:09:25 GMT


So is there no way to force control to return to the main thread and
stop running on the threadpool thread? I can use Invoke etc, but that
still returns control to the existing thread doesn't it (certainly seems
to with my code)?

Apologies for repeating my question but I'm trying to make sure I
understand this properly. This is the first time I've mucked about with
TCP (and indirectly threads) in C# and it seems to introduce an awful
lot of stuffing about simply to keep GUI responsiveness. 90% of my code
will execute after the TCP connection is established, so there is a lot
of extra code that will need to be changed/added. There's got to be an
easier way.

Thanks for your help by the way.

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Jon Skeet [C# MVP] » Mon, 04 Oct 2004 20:01:40 GMT


Just call BeginInvoke to another method and then return from the
current method. That will execute the other method back on the main UI
thread and then let the threadpool thread return to the pool.

You can't "shift" a stack from one thread to another though.


Not really. It's a bit of a pain, but that's how you have to do it.

--
Jon Skeet - < XXXX@XXXXX.COM >
http://www.pobox.com/ ~skeet
If replying to the group, please do not mail me too

CSharp/C# >> NetworkStream.BeginRead and Forms threading

by Stephen Brooker » Tue, 05 Oct 2004 07:22:37 GMT


OK, thanks heaps for the help Jon. Very much appreciated.

Similar Threads

1. Looking for good c# sample NetworkStream BeginRead/EndRead...

Need the correct usage pattern for something like a chat program.

Don't want any threading issues or stack problems.

Kyle!


2. networkstream.beginread, socket error, no callback - CSharp/C#

3. NetworkStream / BeginRead / EndRead / Dataavailable: can't understand MSDN code sample

Hi,

I need to asynchronously read from a network (TCP) stream, and I am
having trouble with retrieving whole blocks; I get a break in the data
block every 1460 bytes which relates to network packet sizes I guess.

To get this fixed, I am trying to follow an example in the MSDN, which
pretty much resembles what I want to do. Since the code (I can't do
this in a static class for example) is not 100% what I need, I
certainly would like to understand what I am doing, but I guess I am
lacking some fundamentals of asynchronous programming since I simply
do not understand the code snippet. Here it is:


public static void myReadCallBack(IAsyncResult ar ){

    NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
    byte[] myReadBuffer = new byte[1024];
    String myCompleteMessage = "";
    int numberOfBytesRead;

    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(NetworkStream_ASync_Send_Receive.myReadCallBack),
                                                   myNetworkStream);  

    }

    // Print out the received message to the console.
    Console.WriteLine("You received the following message : " +
                                myCompleteMessage);
}


I wonder, how myCompleteMessage can ever add up to the complete
message, since it will be reinitialized at every callback, won't it?

If somebody can help me to understand this (what happens
"while(myNetworkStream.DataAvailable){...}") , I would be most
grateful.

Best regards

DC

4. NetworkStream.BeginRead Blocking problem

5. NetworkStream.BeginRead() wierdness

I have a class that wraps a TcpClient object and manages all the async
reading of the socket.  It works really nice, and I use it all over the
place.  But there's this ONE INSTANCE where I create one of these things and
it WON'T read data.  If I set a breakpoint in my EndRead callback, it never
goes off.  NOTHING is different from anywhere else I use this class, its
just this one place.

Now, if I create a second constructor for my class that DOESN'T start off
the async reading process (basically, never calls BeginRead()), subsequent
Read()s will receive data.  Additionally, if I do a loop like this:

while(!networkStream.DataAvailable)
   Sleep(250);

networkStream.BeginRead(...)

Then the class works like it does everywhere else.  Its like, in this one
instance (and this instance isn't any different than anywhere else I use
this class), I can't just do a BeginRead() and wait for data to come in.  I
have to loop and check DataAvailable before calling BeginRead().

Any suggestions?


6. NetworkStream BeginRead & callback invocation - .Net Framework

7. TcpClient BeginRead not spawning new thread

8. TCPClient BeginRead and thread problem - .Net Framework