Changes in Target Machine Visibility in Mobilized .NET* Applications


Challenge

Detect IPEndPoint visibility changes in a mobilized .NET* application. Application developers must ask two questions related to changes in the visibility of IPEndPoints: "How can I tell if my remote system is no longer available so I can stop trying to transfer data to it?" and "How can I tell if my remote system has appeared so I can start communicating with it?" If we combine these two questions with the two possible data transfer situations that we might be in at any time (we are either transferring data, or we aren't), we can deduce the following matrix:

  Currently Transferring Data?
IPEndPoint Change Type Yes No
Appearance Irrelevant Relevant
Disappearance Relevant Irrelevant

 

Logically, only two of these situations are relevant. If we are currently transferring data, the sudden appearance of our target IP EndPoint is not likely; we are currently transferring data to/from it. However, we do want to know whether it has disappeared. Conversely, if we are not currently transferring data, we probably don't care whether our target EndPoint disappears. However, we might get data to send, and therefore we want to be notified when an End int becomes visible.


Solution

Create an event to notify us that the EndPoint to which we are currently transferring information is no longer visible using the SocketException that gets thrown when our active Socket.Send() or Socket.Receive() call is disconnected:

//Establish Socket connection
try
{
bConnected = true;
s.Send(sBuffer);
s.Receive(rBuffer);
}
catch(SocketException se)
{
bConnected = false;
//determine what went wrong
switch( se.ErrorCode )
{
case 10165:
//...
}
}

 

Regarding the answer to the second question ("Has my remote service appeared?"), it would be nice if we could register for an event to notify us when our IPEndPoint was available. Here's our event handler:

//This method gets called when our IPEndPoint is available
public void EndPointAvailableEventHandler (
EndPointAvailableEventArgs args )
{
//args contains the connected socket
args.getSocket().Send(…);
}

 

Here's the method we call to register for the event:

//Call this to register for the IPEndPointAvailable event
public void NotifyIPEndPointAvailable(
IPEndPoint RemoteEndPoint,
EndPoint
ailableEventHandler callbackFunction )
{
this.m_remoteEndPoint = RemoteEndPoint;
this.m_callbackFunction = callbackFunction;
}

 

After we've registered, we send the monitor thread going and wait for notification:

//Call this from a separate thread
public void PollForEndPoint(int iPollingInterval)
{
bool bConnected = false;
while ( m_bAlive && !bConnected )
{
//make sure we start out disconnected
Socket s = new Socket (...);

try
{
s.Connect( m_remoteEndPoint );
if( this.m_callbackFunction != null )
{
m_callbackFunction(
new EndPointAvailableEventArgs( s ) );
}
bConnected = true;
}
catch (SocketException se )
{
Thread.Sleep( iPollingInterval ); //try again in a bit
}
}
}

 

The advantage of this method is that we know for sure that the service on our remote machine (and not just the machine) is either up or down. The disadvantage is that we have to tweak the Socket object in order to get the status change information within a reasonable amount of time. By tweaking the send and receive buffer sizes, and by turning off the Nagle algorithm, we can be notified almost immediately when our service disappears in the middle of a transfer; but we do sacrifice some network efficiency. And to get the same immediacy on our service appearance event, we really should use the asynchronous BeginConnect() method and timeout sooner than the sockets sub-system default:

//Call this from a separate thread
public void PollForEndPoint(int iPollingInterval, int iTimeOut)
{
bool bConnected = false;
while ( m_bAlive && !bConnected )
{
try
{
//WaitOne() calls must block until Set() is called
m_autoResetEvent.Reset();
Socket s = new Socket(...);

//Deleate the blocking connection
//call to another thread
s.BeginConnect( remoteEndPoint,
new AsyncCallback( myAsyncConnectionCallback ),
s ); //Give that thread our socket object

//Give the other thread 5 seconds to make a connection
if ( m_autoResetEvent.WaitOne( iTimeOut, false ) )
{
//The socket connected in time:
//we have a valid socket
if( this.m_callbackFunction != null )
{
m_callbackFunction(
new EndPointAvailableEventArgs( s ) );
}
bConnected = true;
}
else
{
//We timed out and we don't have a valid socket
//try again in a bit
Thread.Sleep( iPollingInterval );
}
}
catch (SocketException se )
{
//Figure out what happened
}
}
}

 

This item is part of a series of items that present sample implementations to obtain network-connection information using the classes found in the .NET Framework:

 


Source

Mobilized .NET* Applications

 


Categories:
For more complete information about compiler optimizations, see our Optimization Notice.