Return-Path: X-Original-To: apmail-tomcat-users-archive@www.apache.org Delivered-To: apmail-tomcat-users-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 59C6510609 for ; Fri, 5 Jul 2013 23:49:33 +0000 (UTC) Received: (qmail 35751 invoked by uid 500); 5 Jul 2013 23:49:30 -0000 Delivered-To: apmail-tomcat-users-archive@tomcat.apache.org Received: (qmail 35669 invoked by uid 500); 5 Jul 2013 23:49:29 -0000 Mailing-List: contact users-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Users List" Delivered-To: mailing list users@tomcat.apache.org Received: (qmail 35660 invoked by uid 99); 5 Jul 2013 23:49:29 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 05 Jul 2013 23:49:29 +0000 X-ASF-Spam-Status: No, hits=1.5 required=5.0 tests=HTML_MESSAGE,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of stewart.vince@gmail.com designates 209.85.216.182 as permitted sender) Received: from [209.85.216.182] (HELO mail-qc0-f182.google.com) (209.85.216.182) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 05 Jul 2013 23:49:22 +0000 Received: by mail-qc0-f182.google.com with SMTP id e10so1494365qcy.27 for ; Fri, 05 Jul 2013 16:49:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type; bh=WQ015rUruO3T57Av5lR9UyHWV3o6FH9qjzdpqV4BkG4=; b=fCeq69OwuBK4avj5ri9D2WCAbN59F02h1Yu56yBWDYu9sKnM1fzdGz15lqJg0qHuhp JqIcwseN0XzwDM94kyVTEl2dGCdpMRdDtgMxSAPar/o0W/DnuQiw2nXEzK0A4ySlWqPR nnydvMCpqwei9kBEbnqh8eRSGK+F9VNGNv3kWEaQ1oZ1HsWvM7rgHfANcuWqsueKQQNZ rd8YFnXnr0BnZqgDA/8hWitdnMB5kItWpcZUhcrE+cgSsShPXFaIitzNXwVbzJORgyzp 02BifiZJp7ybrsuQ7BEsLhIVQoTe0fT5VeT4jGXQTyg/cMVqKHJsgIHyTUHSsI6DC7Fb 9x9A== MIME-Version: 1.0 X-Received: by 10.49.85.4 with SMTP id d4mr7487746qez.10.1373068141208; Fri, 05 Jul 2013 16:49:01 -0700 (PDT) Received: by 10.49.106.8 with HTTP; Fri, 5 Jul 2013 16:49:01 -0700 (PDT) In-Reply-To: References: <42B9B997-E1EF-4C24-A3A1-48A4D704ABB5@j-b-s.de> <51D3270F.8090906@christopherschultz.net> Date: Sat, 6 Jul 2013 11:49:01 +1200 Message-ID: Subject: Re: Share info across different sessions & servers From: Vince Stewart To: Tomcat Users List Content-Type: multipart/alternative; boundary=047d7bb03e6acf2b3804e0cc5655 X-Virus-Checked: Checked by ClamAV on apache.org --047d7bb03e6acf2b3804e0cc5655 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable hi Jose, here is a working demo for exchanging messages between remote hosts using tribes import java.io.IOException; import java.io.Serializable; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Enumeration; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.catalina.tribes.ByteMessage; import org.apache.catalina.tribes.Channel; import org.apache.catalina.tribes.ChannelException; import org.apache.catalina.tribes.Member; import org.apache.catalina.tribes.MembershipListener; import org.apache.catalina.tribes.ChannelListener; import org.apache.catalina.tribes.group.GroupChannel; import org.apache.catalina.tribes.membership.StaticMember; /** * * @author vince * demonstration of tribes messaging between remote hosts * three jar files are required (org.apache) catalina.jar catalina-tribes.jar tomcat-embed-logging-juli.jar compile and run with following arguments java -jar jarfileName.jar ss java -jar jarfileName.jar xx.xx.xx.xx NNNN where jarfileName is whatever you call your jar file ss is the literal argument "ss" for the machine designated as "superserver" (sort of arbitrary) for machines other than superserver: xx.xx.xx.xx is the IPv4 address for the superserver machine NNNN is relevant port number Note that tribes normally uses port 4000. However if you run the application at superserver first you will then know which port number tribes is using (could be 4001, 4002 ...) Note also that if the superserver is part of a LAN, there will be a router involved; the remote applications will then need to point to the router IP address and the router port that is redirected to the machine/port running tribes (more of this below) If non-superserver machines use a router, these also have to have appropriate redirections set up. Some log output refers to clustering functionality operating. This does not seem to interfere with the messaging operations used. I have not looked into any possible mechanisms to suppress clustering threads. A very important limitation to remote messaging (and a possible solution) is discussed here. http://tomcat.10.x6.nabble .com/overcoming-a-message-size-limitation-in-tribes-parallel-messaging-with= -NioSender-tt4995446.html */ public class TribesRemote { static TribesRemote tribesRemote; static Charset UTF8=3DCharset.forName("UTF-8"); static int membersOnLine=3D0; ChannelListener msgListener;// =3D new MyMessageListener(this); MembershipListener mbrListener;// =3D new MyMemberListener(); StaticMember superServerStaticMember; boolean amSuperServer=3Dfalse; private long lastMessageReceived; String remoteHostIPv4Address; int remoteHostPort; Channel myChannel; public static void log(String s){ System.out.println("INFO: "+s); } public static void log(Exception ex){ System.out.println("ERROR "+ex.getMessage()); //Logger.getLogger(TribesRemote.class.getName()).log(Level.SEVERE, null, ex);//uncomment here for detailed error msg } public static void main(String[]args) throws IOException, ChannelException{ TribesRemote.tribesRemote=3Dnew TribesRemote(args); TribesRemote.tribesRemote.engage(); } TribesRemote(String[] args) throws IOException, ChannelException{ log(this.addressesForThisMachine()); remoteHostIPv4Address=3D"xx.xx.xx.xx"; //actual superserver address may be placed here remoteHostPort=3D4000; //actual superserver port may be placed here if(args.length=3D=3D0){ log("TribesRemote has been lauched with zero arguments"); } else{ String argz=3D""; for(int i=3D0;i1){ // otherwise subservers can be started using two arguments remoteHostIPv4Address=3Dargs[0]; // IPv4 adddress in xx.xx.xx.xx format where x is numeric remoteHostPort=3DInteger.parseInt(args[1]); //the port number which tribes starts on } if(args[0].equalsIgnoreCase("ss")){ ///NB superserver started with singular argument "ss" amSuperServer=3Dtrue; log("this is deginated superserver and will wait for members to introduce themselves"); } else{ superServerStaticMember=3Dnew StaticMember(remoteHostIPv4Address,remoteHostPort,0); } } //tribes always uses 4000 if available (otherwise it uses 4001, 4002 etc) //this application will output the actual tribes address =3D> std output //but setting remoteHostPort to 4000 may not be appropriate if you have a router //if you have a router then the remote host needs to know the IPv4 for the router and //the redirection port number pointing to a tribes socket for a LAN machine //for example: //the remote router has fixed IP address say 203.12.32.235 //the remote machine running tribes (on p4000) has fixed LAN address say 192.168.1.63 //(in Linux you set fixed LAN IP address in the '/etc/hosts' file) //lets say you create a port-forwarding in the router so port 45555 redirects to 192.168.1.63 / port 4000 //in such a case the value for remoteHostIPv4Address will be 203.12.32.235 //and remoteHostPort will be 45555 //ie {203.12.32.235 , 45555} =3D> redirects to =3D= > {192.168.1.63 , 4000} //if there is no router (say you have 2 VPS), then no redirect is required //whereupon remoteHostPort will probably be 4000 (as long as that address is free when tribes starts) msgListener =3D new MyMessageListener(); mbrListener =3D new MyMemberListener(); myChannel =3D new GroupChannel(); myChannel.addMembershipListener(mbrListener); myChannel.addChannelListener(msgListener); myChannel.start(Channel.DEFAULT); log("TRIBES HAS STARTED ON PORT: "+Integer.toString(getLocalPort())); } void sendMessage(String message,Member member) throws ChannelException{ Member[] group =3D new Member[]{member}; this.myChannel.send(group,new ByteMessage(message.getBytes(UTF8)),Channel.SEND_OPTIONS_DEFAULT); } String addressesForThisMachine() throws SocketException{ String ss=3D"network addresses for this machine: "; Enumerationee; Enumerationei; ei=3DNetworkInterface.getNetworkInterfaces(); while(ei.hasMoreElements()){ ee=3D((NetworkInterface)ei.nextElement()).getInetAddresses(); while(ee.hasMoreElements()){ ss=3Dss+ee.nextElement().getHostAddress()+"; "; } } return ss; } /* * subserver will run this */ private void engageInDialogue(){ do{ try{ this.sendMessage("* hello superserver *",superServerStaticMember); } catch (ChannelException ex) { TribesRemote.log(ex); } try { Thread.currentThread().sleep(10000); } catch (InterruptedException ex) { System.exit(0); } if(System.currentTimeMillis()-lastMessageTime()>12000){ log("no messages in last 12 seconds"); } }while(true); } /* * superserver will run this */ private void waitForMessages(){ do{ try{ Thread.currentThread().sleep(10000); } catch (InterruptedException ex) { System.exit(0); } }while(true); } int getLocalPort() { return this.myChannel.getLocalMember(true).getPort(); } private void engage(){ if(this.amSuperServer){ this.waitForMessages(); } else{ this.engageInDialogue(); } } private long lastMessageTime() { return this.lastMessageReceived; } void messageReceived(String message, Member sender) throws ChannelException { this.lastMessageReceived=3DSystem.currentTimeMillis(); if(this.amSuperServer){ this.sendMessage(message + " ((hello back ))",sender); } } private static class MyMessageListener implements ChannelListener{ @Override public void messageReceived(Serializable s,Member sender){ byte[] b=3D((ByteMessage)s).getMessage(); String message=3Dnew String(b,TribesRemote.UTF8); TribesRemote.log("message received: "+message); try{ TribesRemote.tribesRemote.messageReceived(message,sender); } catch (ChannelException ex) { TribesRemote.log(ex); } } @Override public boolean accept(Serializable msg, Member sender) { return true; } } //this is part of clustering that has not been removed from tribes private static class MyMemberListener implements MembershipListener{ @Override public void memberAdded(Member member){ //TribesRemote.tribesRemote.memberDetected(member); } @Override public void memberDisappeared(Member member){ //TribesRemote.tribesRemote.memberGone(member); } } } On Thu, Jul 4, 2013 at 6:57 PM, Jose Mar=EDa Zaragoza wrote: > Thanks Vince. > I'll take a look , but , it doesn't look trivial , not at all > > Regards > > > 2013/7/4 Vince Stewart > > > Hi Jose, > > > > a couple of things, > > 1) I use embedded Tomcat to build my application and this has allowed m= e > to > > maintain 2 single-line patches in tribes classes by adding tribes sourc= e > > code to my compilations. However those patches are only necessary with > > large messages that take more than 3 seconds to be transmitted from the > > transmitting machine to the Internet Service Provider machine (approx 0= .5 > > meg for my system). There is a config setting (Sender/Transport/timeout= ) > > that's supposed to alter this 3 second timeout limit but I'm not sure i= t > > works. > > 2) The implementation is not at all trivial. You have to register > > StaticMember objects because usual member discovery does not work over > > wide-area network (WAN). I allocate one machine as "SuperServer" and al= l > > other machines have to enroll with SuperServer at startup. All machines > > need to have a unique combination of Ipv4 address and port number (whic= h > > might represent a redirection port for use by the router whereupon > > networked machines also need LAN addresses set). Once registration is > > complete, all sub-Server machines can send/receive SuperServer and vice > > versa. > > > > There is a tutorial on-line which is adequate but not for WAN. I think > you > > have at least two weeks of work in front of you using tribes but I am > very > > happy I used this method. > > None of my code would add much (except confusion) to that in the > tutorial. > > Make sure you start without multicast enabled as it currently is suitab= le > > only for LAN. > > > > ///Class Constructor > > public ServerMessaging() throws SocketException{ > > this.myChannel=3Dnew GroupChannel(); > > ChannelListener msgListener =3D new ServerMessaging.MyMessageListener(= ); > > MembershipListener mbrListener =3D new ServerMessaging.MyMemberListene= r(); > > myChannel.addMembershipListener(mbrListener); > > myChannel.addChannelListener(msgListener); > > try{ > > > > > > > myChannel.start(Channel.MBR_TX_SEQ|Channel.MBR_RX_SEQ|Channel.SND_TX_SEQ|= Channel.SND_RX_SEQ);//no > > multicast > > } > > catch(ChannelException e){ > > U.log(e); > > } > > } > > > > public void detectOrderNumber_EnrollWithSuperServer() throws > > ChannelException{ > > setMyServerOrderStatus(); // machine reads its mac address or some file= ; > > then from a table will set serverOrderNumber to 0 for superserver ; > others > > 1,2,3... > > if(this.getServerOrderNumber()=3D=3D0){ ////meaning this is the super= server > > someObject.doSomeThingMaybe(); > > } > > else{ > > this.sendAckRequiredMessage(0,"Enrollment"); /// first argument > specifies > > SuperServer, member 0 (a table will need to be provided to hold IPv4 > > address and port for each member) > > } > > } > > > --=20 Vince Stewart --047d7bb03e6acf2b3804e0cc5655--