473,396 Members | 1,938 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,396 software developers and data experts.

Returning object from AsyncCallback called inside a threaded Infinite loop

I'm having trouble returning an object from an AsyncCallback called inside a
threaded infinite loop.

I'm working on a Peer2Peer app that uses an AsyncCallback to rerieve the
data from the remote peer. I have no problem connecting the peers and
streaming Network Streams. When the incoming data is finished recieving, I
act upon it. This works great as long as all of the code is inside my form.

I want to build the networking code into a seperate assembly (to be used by
a server and client apps). It works fine but I can't return the value back
to the Main Form. How can I pass back the retrieved data through the
following steps?? Or, any other strategies on how to tackle this problem?

The Current Process
I start the listener inside a thread and begin an infinite loop to check for
a client connection. When a client connects I call a method that starts the
..BeginRead on the Network Stream. The .BeginRead uses an AsyncCallback
delegate called 'OnReadComplete' and passes a StateObject with the connected
socket.. Inside OnReadComplete, I transfer the callback object to a new
StateObject. I recieve data in 256 byte chunks until the bytes recieved
equals 0. Then I act on that data.

Some example code:

** State Object
----------------
public class StateObject
{
public System.Net.Sockets.Socket socket;
public byte[] buffer = new byte[256];
public NetworkStream networkStream;

public AsyncCallback callbackRead;
}

** Infinite loop used after starting listener
------------------------------------------
// keep listening until you recieve a connection
for (;;)
{
// if client connects, accept the connection
// and return a new socket named socketForClient
// while tcpListener keeps listening
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
StateObject handler = new StateObject();
handler.socket = socketForClient;
handler.networkStream = new NetworkStream(socketForClient);
handler.callbackRead = new AsyncCallback(this.OnReadComplete);
StartRead(handler);
}
}

** StartRead
-------------
public void StartRead(StateObject handler)
{
handler.networkStream.BeginRead(
handler.buffer, 0, handler.buffer.Length, handler.callbackRead, handler);
}

** OnReadComplete
----------------------
private void OnReadComplete( IAsyncResult ar )
{
// Get the socket
StateObject newSocket = (StateObject)ar.AsyncState;
Socket client = newSocket.socket;

// Get the networkStream
NetworkStream readStream = new NetworkStream(newSocket.socket);

int bytesRead = readStream.EndRead(ar);

// If there is data left to be retieved
if( bytesRead > 0 )
{
string s = System.Text.Encoding.ASCII.GetString( newSocket.buffer, 0,
bytesRead );
readStream.BeginRead( newSocket.buffer, 0, newSocket.buffer.Length,
newSocket.callbackRead, newSocket);
// Store message into string.
message += s;
}
// The incoming stream has finished
else
{
// Act on Incoming Message
actOn(message);

// Close out all objects
newSocket.networkStream.Close();
newSocket.socket.Close();
newSocket.networkStream = null;
newSocket.socket = null;
message = null;
}
}
Thanks,
Jim
Nov 15 '05 #1
1 5179
Jim:

I'm not entirely sure that I understand the question. Let me throw what I
picked up back at you, and you can maybe correct me if I'm wrong:
I assume that the code that you posted all works, except that you have a
scoping issue where you cannot inform the main form that something has been
acted upon because inside your OnReadComplete method, the main form (or the
form that you want to notify) is not in scope. Is that correct?

Assuming that's right, you could could always make a reference to the main
form (or better yet, some kind of broker object) available to the thread
code, which would, in turn, add the reference to your state object:
(warning, this is off the cuff, might need adjustment to compile)

So, what could happen would be that you have an "observer" class that sits
between the form(s) and the state class. The class with the thread has a
reference to it, so that it (the observer) can be added to the state class:

form(s) ------ Observer ------ State

State notifies the observer, and the observer fires an event that can be
subscribed by multiple forms or other objects.

public delegate void MessageReceivedEventHandler(object sender,
MessageReceivedEventArgs e);
public class MessageReceivedEventArgs
{
public MessageReceivedEventArgs(string message)
{
this.Message = message;
}

public string Message; // probably make this a property, leaving it out
for brevity
}

public class SocketReadObserver
{
public event MessageReceivedEventHandler MessageReceived;
public void ActOn(string message)
{
if(this.MessageReceived != null)
this.MessageReceived(this, new
MessageReceivedEventArgs(message);
}
}

Now, your State class calls the SocketReadObserver's ActOnMethod.
You need to somehow have SocketReadObserver in scope. You could use a
singleton for this, or your main form could instance one and pass to the
class that contains the thread. Or, perhaps the object that owns the thread
also owns the observer.

The benefit of breaking it out into an observer is that any object
(including the main form) that is interested in receive events can subscribe
to the event:

public class TheThreadClass
{
public SocketReadObserver Observer;
public void TheInfiniteLoopMethod
{
//same code as before
// except provide the listener to the state class
handler.Observer = this.Observer;
}
}

// state object calls Observer.ActOn(message) when the message completes

// oh, don't forget the main form code:

// main form:
// here's the code that starts the thread:
// note the observer has to be created somewhere
// in this example, the form will do it, but you might want to originate it
elsewhere
...
SocketReadObserver observer = new SocketReadObserver();
theThreadListenerObject.Observer = observer;
observer.MessageReceived += new
MessageReceivedEventHandler(this.MessageReceived);
// note, you can hook as many interested parties as you have to this
event -- system tray item, toolbar item, whatever:

public void MessageReceived(object sender, MessageReceivedEventArgs e)
{
// important: this event will not be called by the main thread, but if
you want to do _anything_ that changes
// a gui control, you _must_ make it happen on the main thread. Use
Invoke for this:
if(this.InvokeRequired)
this.Invoke(new
MessageReceivedEventHandler(this.MessageReceived), object[] {sender, e});
else
{
// do your form stuff here
}

}
PS depending upon what you were doing, there are probably a number of ways
that you can optimize this, I was just trying to get the idea across.

PSS: If this isn't the problem that you've had, I'm sorry for being a
windbag <g>
"Jim P." <tr**********@yahoo.com> wrote in message
news:uq****************@TK2MSFTNGP12.phx.gbl...
I'm having trouble returning an object from an AsyncCallback called inside a threaded infinite loop.

I'm working on a Peer2Peer app that uses an AsyncCallback to rerieve the
data from the remote peer. I have no problem connecting the peers and
streaming Network Streams. When the incoming data is finished recieving, I act upon it. This works great as long as all of the code is inside my form.
I want to build the networking code into a seperate assembly (to be used by a server and client apps). It works fine but I can't return the value back to the Main Form. How can I pass back the retrieved data through the
following steps?? Or, any other strategies on how to tackle this problem?

The Current Process
I start the listener inside a thread and begin an infinite loop to check for a client connection. When a client connects I call a method that starts the .BeginRead on the Network Stream. The .BeginRead uses an AsyncCallback
delegate called 'OnReadComplete' and passes a StateObject with the connected socket.. Inside OnReadComplete, I transfer the callback object to a new
StateObject. I recieve data in 256 byte chunks until the bytes recieved
equals 0. Then I act on that data.

Some example code:

** State Object
----------------
public class StateObject
{
public System.Net.Sockets.Socket socket;
public byte[] buffer = new byte[256];
public NetworkStream networkStream;

public AsyncCallback callbackRead;
}

** Infinite loop used after starting listener
------------------------------------------
// keep listening until you recieve a connection
for (;;)
{
// if client connects, accept the connection
// and return a new socket named socketForClient
// while tcpListener keeps listening
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
StateObject handler = new StateObject();
handler.socket = socketForClient;
handler.networkStream = new NetworkStream(socketForClient);
handler.callbackRead = new AsyncCallback(this.OnReadComplete);
StartRead(handler);
}
}

** StartRead
-------------
public void StartRead(StateObject handler)
{
handler.networkStream.BeginRead(
handler.buffer, 0, handler.buffer.Length, handler.callbackRead, handler); }

** OnReadComplete
----------------------
private void OnReadComplete( IAsyncResult ar )
{
// Get the socket
StateObject newSocket = (StateObject)ar.AsyncState;
Socket client = newSocket.socket;

// Get the networkStream
NetworkStream readStream = new NetworkStream(newSocket.socket);

int bytesRead = readStream.EndRead(ar);

// If there is data left to be retieved
if( bytesRead > 0 )
{
string s = System.Text.Encoding.ASCII.GetString( newSocket.buffer, 0,
bytesRead );
readStream.BeginRead( newSocket.buffer, 0, newSocket.buffer.Length,
newSocket.callbackRead, newSocket);
// Store message into string.
message += s;
}
// The incoming stream has finished
else
{
// Act on Incoming Message
actOn(message);

// Close out all objects
newSocket.networkStream.Close();
newSocket.socket.Close();
newSocket.networkStream = null;
newSocket.socket = null;
message = null;
}
}
Thanks,
Jim

Nov 15 '05 #2

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

Similar topics

13
by: Matthias Kaeppler | last post by:
Hi, I was wondering why library implementors often make getter functions return strings by value (copies). For example, in boost::filesystem the leaf() function returns an std::string by value....
8
by: briforge | last post by:
I am writing a program for the Palm OS in c++. I have already posted this to a palm development forum but I'm desperate for a fix, so I hope this cross-post isn't offensive. My program is...
12
by: Ricardo Pereira | last post by:
Hello all, I have a C# class (in this example, called A) that, in its constructor, starts a thread with a method of its own. That thread will be used to continuously check for one of its...
11
by: Doug Thews | last post by:
I've been working on some samples that use BeginInvoke/EndInvoke. In one example, I call BeginInvoke and pass it an AsyncCallback function pointer. I was messing around with ReaderWriterLocks and...
4
by: Jayme Pechan | last post by:
I have a ATL COM object that is loaded through Interop in a C# application. The COM object fires an event and one of the parameters is another object created inside the object. This object has a...
4
by: grayaii | last post by:
Hi, I have a simple form that handles all its paint functionality like so: this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true); And the entry point to this...
70
by: hstagni | last post by:
When i read a key using getchar() inside a loop, the program stops and wait for a key to be pressed. I actually want the program to continue its execution until a key is pressed. Look at this...
3
by: cosmos22 | last post by:
The following code below shows an example of a infinite while loop. I was wondering how I would incorperate another infinite loop into this , without ruining the actions inside of it. I would like to...
8
by: darren | last post by:
Hi everybody, have a quick look at this code: ===== ===== int main(void) { string msg; makeString(msg); cout << "back in main, result = " << msg << endl;
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.