J
Jim P.
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
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