From be2d18b332eb74b6529e18a8f10abf71fcd7382a Mon Sep 17 00:00:00 2001 From: jestin Date: Fri, 7 Jun 2002 11:18:02 +0000 Subject: doc change for the new release --- src/IvyClient.java | 188 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 138 insertions(+), 50 deletions(-) (limited to 'src/IvyClient.java') diff --git a/src/IvyClient.java b/src/IvyClient.java index 18a50f2..3857631 100755 --- a/src/IvyClient.java +++ b/src/IvyClient.java @@ -20,8 +20,14 @@ import gnu.regexp.*; * * CHANGELOG: * 1.0.12: + * - introducing a Ping and Pong in the protocol, in order to detect the loss of + * connection faster. Enabled through the use of -DIVY_PING variable only + * the PINGTIMEOUT value in milliseconds allows me to have a status of the + * socket guaranteed after this timeout * - right handling of IOExceptions in sendBuffer, the Client is removed from - * the bus + * the bus + * - sendDie goes public, so does sendDie(String) + * - appName visibility changed from private to protected * 1.0.10: * - removed the timeout bug eating all the CPU resources */ @@ -38,10 +44,14 @@ public class IvyClient implements Runnable { final static int SchizoToken = 6; /* avoid race condition in concurrent connexions */ final static int DirectMsg = 7;/* the peer sends a direct message */ final static int Die = 8; /* the peer wants us to quit */ + final static int Ping = 9; /* checks the presence of the other */ + final static int Pong = 10; /* checks the presence of the other */ + final static String MESSAGE_TERMINATOR = "\n"; /* the next protocol will use \r */ final static String StartArg = "\u0002";/* begin of arguments */ final static String EndArg = "\u0003"; /* end of arguments */ + private static boolean debug = (System.getProperty("IVY_DEBUG")!=null) ; private Ivy bus; private Socket socket; @@ -49,19 +59,25 @@ public class IvyClient implements Runnable { private OutputStream out; private Hashtable regexp_in = new Hashtable(); private Hashtable regexp_text = new Hashtable(); - private String appName; private int appPort; - private boolean gardefou=true; private boolean peerCalling; - private Thread client; + private volatile Thread clientThread;// volatile to ensure the quick communication + private Integer clientKey ; + private static boolean doping = (System.getProperty("IVY_PING")!=null) ; + final static int PINGTIMEOUT = 5000; + private PINGER pinger; + private volatile Thread pingerThread; + + // protected variables + String appName; - IvyClient(Ivy bus, Socket socket,boolean peerCalling) throws IOException { + IvyClient(Ivy bus, Socket socket,boolean peerCalling,Integer clientKey) throws IOException { appName = "Unknown"; appPort = 0; this.bus = bus; this.socket = socket; this.peerCalling=peerCalling; - // CHANGE: socket.setSoTimeout(100); + this.clientKey=clientKey; in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = socket.getOutputStream(); Hashtable regexps=bus.regexp_out; @@ -72,14 +88,19 @@ public class IvyClient implements Runnable { send(SchizoToken,bus.applicationPort,bus.appName); // sends our regexps to the peer for (Enumeration e = regexps.keys(); e.hasMoreElements(); ) { - Integer key = (Integer)e.nextElement(); - sendRegexp( key.intValue(),(String)regexps.get(key)); + Integer ikey = (Integer)e.nextElement(); + sendRegexp( ikey.intValue(),(String)regexps.get(ikey)); } send( EndRegexp,0,""); // spawns a thread to manage the incoming traffic on this // socket. We should be ready to receive messages now. - client= new Thread(this); - client.start(); + clientThread = new Thread(this); + clientThread .start(); + if (doping) { + pinger = new PINGER(); + pingerThread=new Thread(pinger); + pingerThread.start(); + } } /** @@ -87,6 +108,8 @@ public class IvyClient implements Runnable { */ public String getApplicationName() { return appName ; } + Integer getClientKey() { return clientKey ; } + /** * allow an Ivy package class to access the list of regexps at a * given time. @@ -98,7 +121,7 @@ public class IvyClient implements Runnable { int getAppPort() { return appPort ; } void sendRegexp(int id,String regexp) { - send(AddRegexp,id,regexp); /* perhaps we should perform some checking here */ + send(AddRegexp,id,regexp); /* perhaps we should perform some checking here */ } public void delRegexp(int id) {send( DelRegexp,id,"");} @@ -124,14 +147,23 @@ public class IvyClient implements Runnable { /** * closes the connexion to the peer. - * @param msg the debug information + * @param notify should I send Bye message ? * the thread managing the socket is stopped */ - void close(String msg) throws IOException { - traceDebug("(closing) "+msg); - gardefou=false; - client.interrupt(); - // socket.close(); // should I ? + void close(boolean notify) throws IOException { + traceDebug("closing connexion to "+appName); + if (doping) { pinger.stopPinging(); } + if (notify) sendBye("hasta la vista"); + stopListening(); + // bus.clientDisconnect(this); + socket.close(); // should I also close in and out ? + } + + void stopListening() { + Thread t = clientThread; + if (t==null) return; // we can be summoned to quit from two path at a time + clientThread=null; + t.interrupt(); } /** @@ -149,31 +181,27 @@ public class IvyClient implements Runnable { * the code of the thread handling the incoming messages. */ public void run() { + Thread thisThread = Thread.currentThread(); + traceDebug("Connected from "+ socket.getInetAddress().getHostName()+ ":"+socket.getPort()); String msg = null; - try { - traceDebug("Connected from "+ socket.getInetAddress().getHostName()+ ":"+socket.getPort()); - while ( gardefou ) { - try { - if ((msg=in.readLine()) != null ) { - newParseMsg(msg); - } - } catch (IvyException ie) { - ie.printStackTrace(); - } catch (InterruptedIOException ioe) { - System.out.println("I have been interrupted. I'm about to leave my thread loop"); - if (!gardefou) break; + while ( clientThread==thisThread ) { + try { + if ((msg=in.readLine()) != null ) { + if (doping && (pingerThread!=null)) pingerThread.interrupt(); + newParseMsg(msg); } + } catch (IvyException ie) { + ie.printStackTrace(); + } catch (InterruptedIOException ioe) { + System.out.println("I have been interrupted. I'm about to leave my thread loop"); + if (thisThread!=clientThread) break; + } catch (IOException e) { + if (clientThread!=thisThread) break; + traceDebug("abnormally Disconnected from "+ + socket.getInetAddress().getHostName()+":"+socket.getPort()); } - traceDebug("normally Disconnected from "+ socket.getInetAddress().getHostName()+":"+socket.getPort()); - socket.close(); - out.close(); - in.close(); - } catch (IOException e) { - traceDebug("abnormally Disconnected from "+ - socket.getInetAddress().getHostName()+":"+socket.getPort()); - } - bus.disconnect(this); - bus.removeClient(this); + } // while + traceDebug("normally Disconnected from "+ appName); } private void sendBuffer( String buffer ) throws IvyException { @@ -183,8 +211,12 @@ public class IvyClient implements Runnable { out.flush(); } catch ( IOException e ) { traceDebug("I can't send my message to this client. He probably left"); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); + // invokes the die applicationListeners + bus.disconnectReceived(this); try { - close("IO Exception"); + close(false); } catch (IOException ioe) { throw new IvyException("close failed"+ioe.getMessage()); } @@ -258,9 +290,32 @@ public class IvyClient implements Runnable { } from=to+1; switch (msgType) { + case Die: + traceDebug("received die Message from " + appName); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); + // invokes the die applicationListeners + bus.dieReceived(this,msgId.intValue()); + // makes the bus die + bus.stop(); + try { + close(false); + } catch (IOException ioe) { + throw new IvyException(ioe.getMessage()); + } + break; case Bye: - bus.die(this,msgId.intValue()); - gardefou=false; + // the peer quits + traceDebug("received bye Message from "+appName); + // first, I'm not a first class IvyClient any more + bus.removeClient(this); + // invokes the die applicationListeners + bus.disconnectReceived(this); + try { + close(false); + } catch (IOException ioe) { + throw new IvyException(ioe.getMessage()); + } break; case AddRegexp: String regexp=s.substring(from,b.length); @@ -305,6 +360,16 @@ public class IvyClient implements Runnable { } bus.callCallback(this,msgId,tab); break; + case Pong: + String paramPong=s.substring(from,b.length); + traceDebug("Ping msg from "+appName+" : "+paramPong); + break; + case Ping: + // I receive a ping. I can answer a pong. + String param=s.substring(from,b.length); + traceDebug("Ping msg from "+appName+" : "+param); + sendPong(param); + break; case Error: String error=s.substring(from,b.length); traceDebug("Error msg "+msgId+" "+error); @@ -314,7 +379,7 @@ public class IvyClient implements Runnable { appPort=msgId.intValue(); if ( bus.checkConnected(this) ) { try { - close("Quitting Application already connected"); + close(false); } catch (IOException ioe) { throw new IvyException("io " + ioe.getMessage()); } @@ -325,20 +390,43 @@ public class IvyClient implements Runnable { String direct=s.substring(from,b.length); bus.directMessage( this, msgId.intValue(), direct ); break; - case Die: - gardefou=false; - bus.die(this,msgId.intValue()); - break; default: throw new IvyException("protocol error, unknown message type "+msgType); } } - private void sendDie() {send(Die,0,"");} - private void sendDie(String message) {send(Die,0,message);} + void sendPong(String s) {send(Pong,0,s);} + void sendPing(String s) {send(Ping,0,s);} + + private void sendBye() {send(Bye,0,"");} + private void sendBye(String message) {send(Bye,0,message);} + + public void sendDie() { send(Die,0,""); } + public void sendDie(String message) {send(Die,0,message);} + private InetAddress getRemoteAddress() { return socket.getInetAddress(); } + + public String toString() { + return "IvyClient "+bus.appName+":"+appName; + } private void traceDebug(String s){ - if (debug) System.out.println("-->IvyClient "+appName+"<-- "+s); + if (debug) System.out.println("-->IvyClient "+bus.appName+":"+appName+"<-- "+s); + } + + class PINGER implements Runnable { + boolean isPinging = false; + public void run() { + isPinging=true; + while (isPinging) { + try { + Thread.sleep(PINGTIMEOUT); + sendPing("are you here ?"); + } catch (InterruptedException ie) { + } + } + } + public void stopPinging() { isPinging=false; pingerThread.interrupt();} } + } // class IvyClient /* EOF */ -- cgit v1.1