650 likes | 720 Views
Chapter 28: Peer-to-Peer Applications and JXTA.
E N D
Chapter 28: Peer-to-Peer Applications and JXTA Outline28.1 Introduction28.2 Client/Server and Peer-to-Peer Applications28.3 Centralized vs. Decentralized Network Applications28.4 Peer Discovery and Searching28.5 Case Study: Deitel Instant Messenger28.6 Defining the Service Interface28.7 Defining the Service implementation28.8 Registering the Service28.9 Find Other Peers28.10 Compiling and Running the Example28.11 Improving Deitel Instant Messenger28.12 Deitel Instant Messenger with Multicast Sockets 28.12.1 Registering the Peer 28.12.2 Finding Other Peers28.13 Introduction to JXTA
28.1 Introduction • Peer-to-peer (P2P) application • Each node performs both client and server functions • Distribution of processing responsibilities
28.2 Client/Server and Peer-to-Peer Applications • Client/Server application • e.g., Yahoo! search engine • Server offers common stores of programs and data • Client access the data provided by servers • Peer-to-peer (P2P) application • All computers act as both client and server
28.3 Centralized vs. Decentralized Network Applications • Centralized server • Weakness: dependency on central server • If central server fails, so does the entire application • Decentralized server • True P2P application • No dependency on single node • If one node fails, the application can exist
28.4 Peer Discovery and Searching • Peer discovery • Finding peers in P2P application • Decentralizing an application often slows peer discovery • Distributed searching • Peer sends search criteria to several nearby peers • Searching performed by several systems
28.5 Case Study: Deitel Instant Messenger • Deitel Instant Messenger • P2P application • Uses Jini to bootstrap (register) users onto the P2P network
28.5 Case Study: Deitel Instant Messenger (cont.) Fig. 28.2 Sample windows of Deitel Instant Messenger.
Enables users to send a remote reference to an IMPeer 1 // IMService.java 2 // IMService interface defines the methods 3 // through which the service proxy 4 // communicates with the service. 5 package com.deitel.advjhtp1.jini.IM.service; 6 7 // Java core packages 8 import java.rmi.*; 9 10 // Deitel packages 11 import com.deitel.advjhtp1.jini.IM.IMPeer; 12 13 publicinterface IMService extends Remote { 14 15 // return RMI reference to a remote IMPeer 16 public IMPeer connect( IMPeer sender ) 17 throws RemoteException; 18 } Fig. 28.3 InterfaceIMServicespecifies how service proxy interacts with the service.Lines 16-17
Specifies the interface for communicating between peers Clients send messages to peers by calling sendMessage 1 // IMPeer.java 2 // Interface that all Peer to Peer apps must implement 3 package com.deitel.advjhtp1.jini.IM; 4 5 //java core packages 6 import java.rmi.*; 7 import java.util.*; 8 9 public interface IMPeer extends Remote 10 { 11 // posts Message to peer 12 publicvoid sendMessage( Message message ) 13 throws RemoteException; 14 15 // information methods 16 public String getName() throws RemoteException; 17 } Fig. 28.4 InterfaceIMPeerspecifies interaction between peers.Line 9Lines 12-13
Messages must be serialized for delivery over RMI Message constructor takes as arguments the sender’s name and message content 1 // Message.java 2 // Message represents an object that can be sent to an IMPeer; 3 // contains the sender and content of the message. 4 package com.deitel.advjhtp1.jini.IM; 5 6 // Java core package 7 import java.io.Serializable; 8 9 publicclass Message implements Serializable 10 { 11 privatestaticfinallong SerialVersionUID = 20010808L; 12 private String from; 13 private String content; 14 15 // Message constructor 16 public Message( String messageSenderName, 17 String messageContent ) 18 { 19 from = messageSenderName; 20 content = messageContent; 21 } 22 23 // get String representation 24 public String toString() 25 { 26 return from + ": " + content + "\n"; 27 } 28 29 // get Message sender's name 30 public String getSenderName() 31 { 32 return from; 33 } Fig. 28.5 ClassMessagedefines an object for sending and receiving messages between peers (part 1).Line 9Lines 16-21
34 35 // get Message content 36 public String getContent() 37 { 38 return content; 39 } 40 } Fig. 28.5 ClassMessagedefines an object for sending and receiving messages between peers (part 2).
28.7 Defining the Service Implementation • Define service implementation • IMServiceImpl • Implements interface IMService • Extends UnicastRemoteObject
Define the service implementation Second constructor takes as a String argument the user’s name, which appears in the PeerList window 1 // IMServiceImpl.java 2 // IMServiceImpl implements IMService interface 3 // is service side of IM application 4 package com.deitel.advjhtp1.jini.IM.service; 5 6 // Java core packages 7 import java.io.*; 8 import java.rmi.server.UnicastRemoteObject; 9 import java.rmi.RemoteException; 10 import java.util.StringTokenizer; 11 12 // Deitel packages 13 import com.deitel.advjhtp1.jini.IM.IMPeer; 14 import com.deitel.advjhtp1.jini.IM.IMPeerImpl; 15 import com.deitel.advjhtp1.jini.IM.Message; 16 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener; 17 18 publicclass IMServiceImpl extends UnicastRemoteObject 19 implements IMService, Serializable { 20 21 privatestaticfinallong SerialVersionUID = 20010808L; 22 private String userName = "Anonymous"; 23 24 // IMService no-argument constructor 25 public IMServiceImpl() throws RemoteException{} 26 27 // IMService constructor takes userName 28 public IMServiceImpl( String name ) throws RemoteException 29 { 30 userName = name; 31 } 32 Fig. 28.6 IMServiceImplservice implementation for our case study(part 1).Line 18Lines 28-31
First peer sends reference of itself to second peer by invoking IMService method connect Second Peer stores first peer’s reference for use when conversation starts Second peer returns reference of itself to first peer 33 // sets service s userName 34 publicvoid setUserName( String name ) 35 { 36 userName = name; 37 } 38 39 // return RMI reference to an IMPeer on the receiver side 40 public IMPeer connect( IMPeer sender ) 41 throws RemoteException 42 { 43 // Make a GUI and IMPeerImpl to be sent to remote peer 44 IMPeerListener listener = 45 new IMPeerListener( userName ); 46 47 IMPeerImpl me = new IMPeerImpl( userName ); 48 me.addListener( listener ); 49 50 // add remote peer to my GUI 51 listener.addPeer( sender ); 52 53 //send my IMPeerImpl to him 54 return me; 55 56 } // end method connect 57 } Fig. 28.6 IMServiceImplservice implementation for our case study(part 2).Line 40Line 51Line 54
GUI for starting peer communication 1 // IMPeerListener.java 2 // IMPeerListener extends JFrame and provides GUI for 3 // conversations with other peers 4 package com.deitel.advjhtp1.jini.IM.client; 5 6 // Java core packages 7 import java.awt.*; 8 import java.awt.event.*; 9 import java.rmi.RemoteException; 10 11 // Java extension packages 12 import javax.swing.*; 13 import javax.swing.text.*; 14 import javax.swing.border.*; 15 16 // Deitel Packages 17 import com.deitel.advjhtp1.jini.IM.IMPeer; 18 import com.deitel.advjhtp1.jini.IM.Message; 19 20 publicclass IMPeerListener extends JFrame { 21 22 // JTextAreas for displaying and inputting messages 23 private JTextArea messageArea; 24 private JTextArea inputArea; 25 26 // Actions for sending messages, etc. 27 private Action sendAction; 28 29 // userName to add to outgoing messages 30 private String userName = ""; 31 32 // IMPeer to send messages to peer 33 private IMPeer remotePeer; 34 Fig. 28.7 IMPeerListeneris the GUI that starts peer communication (part 1).Line 20
35 // constructor 36 public IMPeerListener( String name ) 37 { 38 super( "Conversation Window" ); 39 40 // set user name 41 userName = name; 42 43 // init sendAction 44 sendAction = new SendAction(); 45 46 // create JTextArea for displaying messages 47 messageArea = new JTextArea( 15, 15 ); 48 49 // disable editing and wrap words at end of line 50 messageArea.setEditable( false ); 51 messageArea.setLineWrap( true ); 52 messageArea.setWrapStyleWord( true ); 53 54 JPanel panel = new JPanel(); 55 panel.setLayout( new BorderLayout( 5, 5 ) ); 56 panel.add( new JScrollPane( messageArea ), 57 BorderLayout.CENTER ); 58 59 // create JTextArea for entering new messages 60 inputArea = new JTextArea( 4, 12 ); 61 inputArea.setLineWrap( true ); 62 inputArea.setWrapStyleWord( true ); 63 64 // map Enter key in inputArea area to sendAction 65 Keymap keyMap = inputArea.getKeymap(); 66 KeyStroke enterKey = KeyStroke.getKeyStroke( 67 KeyEvent.VK_ENTER, 0 ); 68 keyMap.addActionForKeyStroke( enterKey, sendAction ); 69 Fig. 28.7 IMPeerListeneris the GUI that starts peer communication (part 2).
70 // lay out inputArea and sendAction JButton in Box 71 Box box = Box.createVerticalBox(); 72 box.add( new JScrollPane( inputArea ) ); 73 box.add( new JButton( sendAction ) ); 74 75 panel.add( box, BorderLayout.SOUTH ); 76 77 // lay out components 78 Container container = getContentPane(); 79 container.add( panel, BorderLayout.CENTER ); 80 81 setSize( 200, 400 ); 82 setVisible( true ); 83 } 84 85 // Action for sending messages 86 privateclass SendAction extends AbstractAction { 87 88 // configure SendAction 89 public SendAction() 90 { 91 putValue( Action.NAME, "Send" ); 92 putValue( Action.SHORT_DESCRIPTION, 93 "Send Message" ); 94 putValue( Action.LONG_DESCRIPTION, 95 "Send an Instant Message" ); 96 } 97 98 // send message and clear inputArea 99 publicvoid actionPerformed( ActionEvent event ) 100 { 101 // send message to server 102 try { 103 Message message = new Message( userName, 104 inputArea.getText() ); Fig. 28.7 IMPeerListeneris the GUI that starts peer communication (part 3).
When user presses JButton, call method sendMessage of remote peer 105 106 // use RMI reference to send a Message 107 remotePeer.sendMessage( message ); 108 109 // clear inputArea 110 inputArea.setText( "" ); 111 displayMessage( message ); 112 } 113 114 // catch error sending message 115 catch( RemoteException remoteException ) { 116 JOptionPane.showMessageDialog( null, 117 "Unable to send message." ); 118 119 remoteException.printStackTrace(); 120 } 121 } // end method actionPerformed 122 123 } // end sendAction inner class 124 125 publicvoid displayMessage( Message message ) 126 { 127 // displayMessage uses SwingUntilities.invokeLater 128 // to ensure thread-safe access to messageArea 129 SwingUtilities.invokeLater( 130 new MessageDisplayer( 131 message.getSenderName(), message.getContent() ) ); 132 } 133 134 // MessageDisplayer displays a new message by appending 135 // the message to the messageArea JTextArea. This Runnable 136 // object should be executed only on the event-dispatch 137 // thread, as it modifies a live Swing component. 138 private class MessageDisplayer implements Runnable { 139 Fig. 28.7 IMPeerListeneris the GUI that starts peer communication (part 4).Line 107
Stores reference to remote IMPeer and set title of conversation window to the name of remote IMPeer 140 private String fromUser; 141 private String messageBody; 142 143 // MessageDisplayer constructor 144 public MessageDisplayer( String from, String body ) 145 { 146 fromUser = from; 147 messageBody = body; 148 } 149 150 // display new message in messageArea 151 publicvoid run() 152 { 153 // append new message 154 messageArea.append( "\n" + fromUser + "> " + 155 messageBody ); 156 157 // move caret to end of messageArea to ensure new 158 // message is visible on screen 159 messageArea.setCaretPosition( 160 messageArea.getText().length() ); 161 } 162 163 } // end MessageDisplayer inner class 164 165 // addPeer takes IMPeer as arg 166 // associates IMPeer with sendAction to send messages 167 publicvoid addPeer( IMPeer peer ) throws RemoteException 168 { 169 remotePeer = peer; 170 171 // change title of window to name of peer 172 setTitle( remotePeer.getName() ); 173 } 174 } Fig. 28.7 IMPeerListeneris the GUI that starts peer communication (part 5).Lines 167-173
Define the peer implementation 1 // IMPeerImpl.java 2 // Implements the IMPeer interface 3 package com.deitel.advjhtp1.jini.IM; 4 5 // Java core packages 6 import java.io.*; 7 import java.net.*; 8 import java.rmi.*; 9 import java.rmi.server.*; 10 import java.util.*; 11 12 // Deitel Packages 13 import com.deitel.advjhtp1.jini.IM.Message; 14 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener; 15 16 17 publicclass IMPeerImpl extends UnicastRemoteObject 18 implements IMPeer { 19 20 private String name; 21 private IMPeerListener output; 22 23 // No argument constructor 24 public IMPeerImpl() throws RemoteException 25 { 26 super(); 27 name = "anonymous"; 28 } 29 // constructor takes userName 30 public IMPeerImpl( String myName ) throws RemoteException 31 { 32 name = myName; 33 } 34 Fig. 28.8 Class IMPeerImplis the IMPeer implementation (part 1).Line 17
Add an object of type IMPeer-Listener that will display the IMPeerImpl’s actions Override method sendMessage to send message to peer 35 publicvoid addListener( IMPeerListener listener ) 36 { 37 output = listener; 38 } 39 40 // send message to this peer 41 publicvoid sendMessage( Message message ) 42 throws RemoteException 43 { 44 output.displayMessage( message ); 45 } 46 47 // accessor for name 48 public String getName() throws RemoteException 49 { 50 return name; 51 } 52 } Fig. 28.8 Class IMPeerImplis the IMPeer implementation (part 2).Lines 35-38Lines 41-45
28.8 Registering the Service • Register (bootstrap) service with peer group
Constructor takes a String that specifies the NameEntry for the service 1 // IMServiceManager.java 2 // IMServiceManager uses JoinManager to find Lookup services, 3 // registers the IMService with the Lookup services, 4 // manages lease renewal 5 package com.deitel.advjhtp1.jini.IM; 6 7 // Java core packages 8 import java.rmi.RMISecurityManager; 9 import java.rmi.RemoteException; 10 import java.io.IOException; 11 12 // Jini core packages 13 import net.jini.core.lookup.ServiceID; 14 import net.jini.core.entry.Entry; 15 16 // Jini extension packages 17 import net.jini.lookup.entry.Name; 18 import net.jini.lease.LeaseRenewalManager; 19 import net.jini.lookup.JoinManager; 20 import net.jini.discovery.LookupDiscoveryManager; 21 import net.jini.lookup.ServiceIDListener; 22 23 // Deitel packages 24 import com.deitel.advjhtp1.jini.IM.service.*; 25 26 publicclass IMServiceManager implements ServiceIDListener { 27 28 JoinManager manager; 29 LookupDiscoveryManager lookupManager; 30 String serviceName; 31 32 // constructor takes name of the service 33 public IMServiceManager( String screenName ) 34 { 35 System.setSecurityManager( new RMISecurityManager() ); Fig. 28.9 Class IMServiceManagerregisters IMServiceImpl with lookup services(part 1).Line 33
Use Jini’s JoinManager class to register the service with all known lookup services 36 37 // sets the serviceName of this service 38 serviceName = screenName; 39 40 // use JoinManager to register SeminarInfo service 41 // and manage lease 42 try { 43 44 // create LookupDiscoveryManager for discovering 45 // lookup services 46 lookupManager = 47 new LookupDiscoveryManager( new String[] { "" }, 48 null, null ); 49 50 // create and set Entry name for service 51 // name used from constructor 52 Entry[] entries = new Entry[ 1 ]; 53 entries[ 0 ] = new Name( serviceName ); 54 55 // create JoinManager 56 manager = new JoinManager( createProxy(), 57 entries, this, lookupManager, 58 new LeaseRenewalManager() ); 59 } 60 61 // handle exception creating JoinManager 62 catch ( IOException exception ) { 63 exception.printStackTrace(); 64 } 65 } // end SeminarInfoJoinService constructor 66 67 // return the LookupDiscoveryManager created by JoinManager 68 public LookupDiscoveryManager getDiscoveryManager() 69 { 70 return lookupManager; Fig. 28.9 Class IMServiceManagerregisters IMServiceImpl with lookup services(part 2).Line 56
71 } 72 73 // create service proxy 74 private IMService createProxy() 75 { 76 // get SeminarProxy for SeminarInfo service 77 try { 78 return( new IMServiceImpl( serviceName ) ); 79 } 80 81 // handle exception creating SeminarProxy 82 catch ( RemoteException exception ) { 83 exception.printStackTrace(); 84 } 85 86 returnnull; 87 88 } // end method createProxy 89 90 // receive notification of ServiceID assignment 91 publicvoid serviceIDNotify( ServiceID serviceID ) 92 { 93 System.err.println( "Service ID: " + serviceID ); 94 } 95 96 // informs all lookup services that service is ending 97 publicvoid logout() 98 { 99 manager.terminate(); 100 } 101 } Fig. 28.9 Class IMServiceManagerregisters IMServiceImpl with lookup services(part 3).
28.9 Find Other Peers • Create GUI enabling user to find other peers
PeerList is the main window of the Deitel Instant Messenger 1 // PeerList.java 2 // Initializes ServiceManager, starts service discovery 3 // and lists all IM services in a window 4 package com.deitel.advjhtp1.jini.IM; 5 6 // Java core packages 7 import java.awt.*; 8 import java.awt.event.*; 9 import java.net.MalformedURLException; 10 import java.util.*; 11 import java.util.List; 12 import java.io.IOException; 13 import java.rmi.*; 14 15 // Java extension packages 16 import javax.swing.*; 17 import javax.swing.event.*; 18 19 // Jini core packages 20 import net.jini.core.lookup.ServiceItem; 21 import net.jini.core.lookup.ServiceTemplate; 22 import net.jini.lookup.*; 23 import net.jini.discovery.LookupDiscoveryManager; 24 import net.jini.lease.LeaseRenewalManager; 25 import net.jini.lookup.entry.Name; 26 import net.jini.core.entry.Entry; 27 import net.jini.core.discovery.LookupLocator; 28 29 // Deitel Packages 30 import com.deitel.advjhtp1.jini.IM.service.IMService; 31 import com.deitel.advjhtp1.jini.IM.client.IMPeerListener; 32 33 publicclass PeerList extends JFrame 34 implements ServiceDiscoveryListener { 35 Fig. 28.10 Class PeerListis the GUI for finding peers (part 1).Lines 33-34
Obtain a ServiceItem that represents the added service Add service proxy to List and add Name to Default-ListModel if Name entry 36 private DefaultListModel peers; 37 private JList peerList; 38 private List serviceItems; 39 private ServiceDiscoveryManager serviceDiscoveryManager; 40 private LookupCache cache; 41 private IMServiceManager myManager; 42 private LookupDiscoveryManager lookupDiscoveryManager; 43 44 // initialize userName to anonymous 45 private String userName = "anonymous"; 46 47 // method called when ServiceDiscoveryManager finds 48 // IM service adds service proxy to serviceItems 49 // adds Service name to ListModel for JList 50 publicvoid serviceAdded( ServiceDiscoveryEvent event ) 51 { 52 // get added serviceItem 53 ServiceItem item = event.getPostEventServiceItem(); 54 Entry attributes[] = item.attributeSets; 55 56 // iterates through attributes to find name 57 for( int i = 0; i < attributes.length; i++ ) 58 59 if ( attributes[ i ] instanceof Name ) { 60 System.out.println( "Added: " + item ); 61 serviceItems.add( item.service ); 62 peers.addElement( 63 ( ( Name )attributes[ i ] ).name ); 64 break; 65 } 66 } // end method serviceAdded 67 68 // empty method ignores seviceChanged event 69 publicvoid serviceChanged( ServiceDiscoveryEvent event ) 70 {} Fig. 28.10 Class PeerListis the GUI for finding peers (part 2).Line 53Lines 57-65
71 72 // removes services from PeerList GUI and data structure 73 // when serviceRemoved event occurs 74 publicvoid serviceRemoved( ServiceDiscoveryEvent event ) 75 { 76 // getPreEvent because item has been removed 77 // getPostEvent would return null 78 ServiceItem item = event.getPreEventServiceItem(); 79 Entry attributes[ ] = item.attributeSets; 80 81 // debug 82 System.out.println( "Remove Event!" ); 83 84 // remove from arraylist and DefaultListModel 85 int index = serviceItems.indexOf( item.service ); 86 87 // print name of person removed 88 if ( index >= 0 ) 89 { 90 System.out.println( "Removing from List:" + 91 serviceItems.remove( index )); 92 93 System.out.println( "Removing from DefList" + 94 peers.elementAt( index ) ); 95 96 peers.removeElementAt( index ); 97 } 98 } // end method ServiceRemoved 99 100 // constructor 101 public PeerList() 102 { 103 super( "Peer List" ); 104 105 System.setSecurityManager( new RMISecurityManager() ); Fig. 28.10 Class PeerListis the GUI for finding peers (part 3).
Use index of selected JList item to retrieve IMService proxy 106 107 // get desired userName 108 userName = JOptionPane.showInputDialog( 109 PeerList.this, "Please enter your name: " ); 110 111 // change title of window 112 setTitle( userName + "'s Peer List Window" ); 113 114 // Init Lists 115 serviceItems = new ArrayList(); 116 117 Container container = getContentPane(); 118 peers = new DefaultListModel(); 119 120 // init components 121 peerList = new JList( peers ); 122 peerList.setVisibleRowCount( 5 ); 123 JButton connectButton = new JButton( "Connect" ); 124 125 // do not allow multiple selections 126 peerList.setSelectionMode( 127 ListSelectionModel.SINGLE_SELECTION ); 128 129 // set up event handler for connectButton 130 connectButton.addActionListener( 131 new ActionListener() { 132 133 publicvoid actionPerformed( ActionEvent event ) 134 { 135 int itemIndex = peerList.getSelectedIndex(); 136 137 Object selectedService = 138 serviceItems.get( itemIndex ); 139 IMService peerProxy = 140 ( IMService )selectedService; Fig. 28.10 Class PeerListis the GUI for finding peers (part 4).Lines 135-138
Create IMPeerListener for IMPeerImpl IMPeerImpl will post all messages sent by remote peer to IMPeerListener 141 142 // send info to remote peer 143 // get RMI reference 144 try { 145 146 // set up gui and my peerImpl 147 IMPeerListener gui = 148 new IMPeerListener( userName ); 149 IMPeerImpl me = 150 new IMPeerImpl( userName ); 151 me.addListener( gui ); 152 153 // Connect myGui to remote IMPeer object 154 IMPeer myPeer = peerProxy.connect( me ); 155 gui.addPeer( myPeer ); 156 } 157 158 // connecting may cause RemoteException 159 catch( RemoteException re ) { 160 JOptionPane.showMessageDialog 161 ( null, "Couldn't Connect" ); 162 re.printStackTrace(); 163 } 164 } 165 } 166 ); // end connectButton actionListener 167 168 // set up File menu 169 JMenu fileMenu = new JMenu( "File" ); 170 fileMenu.setMnemonic( 'F' ); 171 Fig. 28.10 Class PeerListis the GUI for finding peers (part 5).Lines 147-151Lines 154-155
Create dialog box to prompt user for Jini-lookup-service URL 172 // about Item 173 JMenuItem aboutItem = new JMenuItem( "About..." ); 174 aboutItem.setMnemonic( 'A' ); 175 aboutItem.addActionListener( 176 new ActionListener() { 177 publicvoid actionPerformed( ActionEvent event ) 178 { 179 JOptionPane.showMessageDialog( PeerList.this, 180 "Deitel Instant Messenger" , 181 "About", JOptionPane.PLAIN_MESSAGE ); 182 } 183 } 184 ); 185 186 fileMenu.add( aboutItem ); 187 188 // AddLocator item 189 JMenuItem federateItem = 190 new JMenuItem( "Add Locators" ); 191 federateItem.setMnemonic( 'L' ); 192 federateItem.addActionListener( 193 194 new ActionListener() { 195 publicvoid actionPerformed( ActionEvent event ) 196 { 197 // get LookupService url to be added 198 String locator = 199 JOptionPane.showInputDialog( 200 PeerList.this, 201 "Please enter locator in this" + 202 "form: jini://host:port/" ); 203 204 try { 205 LookupLocator newLocator = 206 new LookupLocator( locator ); Fig. 28.10 Class PeerListis the GUI for finding peers (part 6).Lines 189-223
Client registers with newly added lookup service; PeerList window lists all other peers registered with new lookup service 207 208 // make one element LookupLocator array 209 LookupLocator[] locators = { newLocator }; 210 211 // because addLocators takes array 212 lookupDiscoveryManager.addLocators( locators ); 213 } 214 215 catch( MalformedURLException urlException) { 216 217 JOptionPane.showMessageDialog( 218 PeerList.this, "invalid url" ); 219 } 220 } 221 } 222 ); 223 fileMenu.add( federateItem ); 224 225 // set up JMenuBar and attach File menu 226 JMenuBar menuBar = new JMenuBar(); 227 menuBar.add ( fileMenu ); 228 setJMenuBar( menuBar ); 229 230 // handow window closing event 231 addWindowListener( 232 new WindowAdapter(){ 233 publicvoid windowClosing( WindowEvent w ) 234 { 235 System.out.println( "CLOSING WINDOW" ); 236 237 // disconnects from lookup services 238 myManager.logout(); 239 System.exit( 0 ); 240 } 241 } Fig. 28.10 Class PeerListis the GUI for finding peers (part 7).Line 212
Create the IMServiceManager, using userName to name the peer 242 ); 243 244 // lay out GUI components 245 peerList.setFixedCellWidth( 100 ); 246 JPanel inputPanel = new JPanel(); 247 inputPanel.add( connectButton ); 248 249 container.add( new JScrollPane( peerList ) , 250 BorderLayout.NORTH ); 251 container.add( inputPanel, BorderLayout.SOUTH ); 252 253 setSize( 100, 170 ); 254 setVisible( true ); 255 256 // peer list displays only other IMServices 257 Class[] types = new Class[] { IMService.class }; 258 ServiceTemplate IMTemplate = 259 new ServiceTemplate( null, types, null ); 260 261 // Initialize IMServiceManager, ServiceDiscoveryManager 262 try { 263 myManager = new IMServiceManager( userName ); 264 265 // store LookupDiscoveryManager 266 // generated by IMServiceManager 267 lookupDiscoveryManager = myManager.getDiscoveryManager(); 268 269 // ServiceDiscoveryManager uses lookupDiscoveryManager 270 serviceDiscoveryManager = 271 new ServiceDiscoveryManager( lookupDiscoveryManager, 272 null ); 273 274 // create a LookupCache 275 cache = serviceDiscoveryManager.createLookupCache( 276 IMTemplate, null, this ); Fig. 28.10 Class PeerListis the GUI for finding peers (part 8).Line 263
277 } 278 279 // catch all exceptions and inform user of problem 280 catch ( Exception managerException) { 281 JOptionPane.showMessageDialog( null, 282 "Error initializing IMServiceManger" + 283 "or ServiceDisoveryManager" ); 284 managerException.printStackTrace(); 285 } 286 } 287 288 publicstaticvoid main( String args[] ) 289 { 290 new PeerList(); 291 } 292 } Fig. 28.10 Class PeerListis the GUI for finding peers (part 9).
28.10 Compiling and Running the Example • 1. Compile classes • 2. Compile remote classes via rmic • 3. Start rmid • 4. Start HTTP server • 5. Start lookup service
28.11 Improving Deitel Instant Messenger • Limitations • Not secure • Not scalable • Solutions • Filters • limit the number of service proxies that ServiceDiscoveryManager downloads • Distributed searches • Facilitate locating peers
28.12 Deitel Instant Messenger with Multicast Sockets • True P2P application • Each node must run lookup service • Requires significant amounts of memory and processor time • Solution: • Use Multicast sockets • Advertise and find peers in network
28.12.1 Registering the Peer • Jini implementation • provided mechanism to register and find peers • We must implement this mechanism via multicast sockets
MulticastSendingThread multicasts a peer’s presence 1 // MulticastSendingThread.java 2 // Sends a multicast periodically containing a remote reference 3 // to the IMServiceImpl object 4 package com.deitel.advjhtp1.p2p; 5 6 // Java core packages 7 import java.net.MulticastSocket; 8 import java.net.*; 9 import java.rmi.*; 10 import java.rmi.registry.*; 11 import java.io.*; 12 13 // Deitel core packages 14 import com.deitel.advjhtp1.jini.IM.service.IMServiceImpl; 15 import com.deitel.advjhtp1.jini.IM.service.IMService; 16 17 publicclass MulticastSendingThread extends Thread 18 implements IMConstants { 19 20 // InetAddress of group for messages 21 private InetAddress multicastNetAddress; 22 23 // MulticastSocket for multicasting messages 24 private MulticastSocket multicastSocket; 25 26 // Datagram packet to be reused 27 private DatagramPacket multicastPacket; 28 29 // stub of local peer 30 private IMService peerStub; 31 32 // flag for terminating MulticastSendingThread 33 privateboolean keepSending = true; 34 35 private String userName; Fig. 28.11 MulticastSendingThreadbroadcasts DatagramPackets (part 1).Line 17
Call createRegistry to instantiate an RMI registry on port 1099 Rebind IMServiceImpl to RMI registry Instantiate MulticastSocket for sending messages to peers 36 37 // MulticastSendingThread constructor 38 public MulticastSendingThread( String myName ) 39 { 40 // invoke superclass constructor to name Thread 41 super( "MulticastSendingThread" ); 42 43 userName = myName; 44 45 // create a registry on default port 1099 46 try { 47 Registry registry = 48 LocateRegistry.createRegistry( 1099 ); 49 peerStub = new IMServiceImpl( userName ); 50 registry.rebind( BINDING_NAME, peerStub ); 51 } 52 catch ( RemoteException remoteException ) { 53 remoteException.printStackTrace(); 54 } 55 56 try { 57 58 // create MulticastSocket for sending messages 59 multicastSocket = 60 new MulticastSocket ( MULTICAST_SENDING_PORT ); 61 62 // set TTL for Multicast Socket 63 multicastSocket.setTimeToLive( MULTICAST_TTL ); 64 65 // use InetAddress reserved for multicast group 66 multicastNetAddress = InetAddress.getByName( 67 MULTICAST_ADDRESS ); 68 69 // create greeting packet 70 String greeting = new String( HELLO_HEADER + userName ); Fig. 28.11 MulticastSendingThreadbroadcasts DatagramPackets (part 2).Lines 47-48Line 49Lines 59-60
Create message packet containing peer’s name Send message via MulticastSocket 71 72 multicastPacket = new DatagramPacket( 73 greeting.getBytes(), greeting.getBytes().length, 74 multicastNetAddress, MULTICAST_LISTENING_PORT ); 75 } 76 77 // MULTICAST_ADDRESS IS UNKNOWN HOST 78 catch ( java.net.UnknownHostException unknownHostException ) 79 { 80 System.err.println( "MULTICAST_ADDRESS is unknown" ); 81 unknownHostException.printStackTrace(); 82 } 83 84 // any other exception 85 catch ( Exception exception ) 86 { 87 exception.printStackTrace(); 88 } 89 } 90 91 // deliver greeting message to peers 92 publicvoid run() 93 { 94 while ( keepSending ) { 95 96 // deliver greeting 97 try { 98 99 // send greeting packet 100 multicastSocket.send( multicastPacket ); 101 102 Thread.sleep( MULTICAST_INTERVAL ); 103 } 104 Fig. 28.11 MulticastSendingThreadbroadcasts DatagramPackets (part 3).Lines 72-74Lines 100
Send message indicating that the peer is leaving network 105 // handle exception delivering message 106 catch ( IOException ioException ) { 107 ioException.printStackTrace(); 108 continue; 109 } 110 catch ( InterruptedException interruptedException ) { 111 interruptedException.printStackTrace(); 112 } 113 114 } // end while 115 116 multicastSocket.close(); 117 118 } // end method run 119 120 // send goodbye message 121 publicvoid logout() 122 { 123 String goodbye = new String( GOODBYE_HEADER + userName ); 124 System.out.println( goodbye ); 125 multicastPacket = new DatagramPacket( 126 goodbye.getBytes(), goodbye.getBytes().length, 127 multicastNetAddress, MULTICAST_LISTENING_PORT ); 128 129 try { 130 multicastSocket.send( multicastPacket ); 131 132 Naming.unbind( BINDING_NAME ); 133 } 134 135 // error multicasting 136 catch ( IOException ioException ) { 137 System.err.println( "Could not Say Goodbye“ ); 138 ioException.printStackTrace(); 139 } Fig. 28.11 MulticastSendingThreadbroadcasts DatagramPackets (part 4).Lines 123-130
140 141 // unbinding may cause many possible exceptions 142 catch ( Exception unbindingException ) { 143 unbindingException.printStackTrace(); 144 } 145 146 keepSending = false; 147 148 } 149 } Fig. 28.11 MulticastSendingThreadbroadcasts DatagramPackets (part 5).
Definition of several constants used in the multicast-socket version of Deitel Instant Messenger 1 // IMConstants.java 2 // contains constants used by IM application 3 package com.deitel.advjhtp1.p2p; 4 5 publicinterface IMConstants { 6 7 publicstaticfinal String MULTICAST_ADDRESS = "228.5.6.10"; 8 9 publicstaticfinalintMULTICAST_TTL = 30; 10 11 // port on local machine for broadcasting 12 public static final intMULTICAST_SENDING_PORT = 6800; 13 14 // port on local machine for receiving broadcasts 15 publicstatic final intMULTICAST_RECEIVING_PORT = 6789; 16 17 // port on multicast ip address to send packets 18 public static final intMULTICAST_LISTENING_PORT = 6789; 19 20 public static final String HELLO_HEADER = "HELLOIM: "; 21 22 public static final String GOODBYE_HEADER = "GOODBYE: "; 23 24 // time in milliseconds to wait between each multicast 25 public static final intMULTICAST_INTERVAL = 10000; 26 27 // how many MUTLICAST_INTERVALS before LEASE EXPIRATION 28 public static final intPEER_TTL = 5; 29 30 public static final intMESSAGE_SIZE = 256; 31 32 public static String BINDING_NAME = "IMSERVICE"; 33 34 } Fig. 28.12 InterfaceIMConstantsdefines Deitel-Instant-Messenger constants.Lines 5-34
28.12.2 Finding Other Peers • Jini implementation • Listed new peers • Removed peers that left network
MulticastReceiving-Thread listens for DatagramPackets that contain notifications of peers joining and leaving network 1 // MulticastReceivingThread.java 2 // Receive and process multicasts from multicast group 3 package com.deitel.advjhtp1.p2p; 4 5 // Java core packages 6 import java.net.MulticastSocket; 7 import java.net.*; 8 import java.io.*; 9 import java.util.*; 10 11 // Deitel packages 12 import com.deitel.advjhtp1.p2p.PeerDiscoveryListener; 13 14 publicclass MulticastReceivingThread extends Thread 15 implements IMConstants { 16 17 // HashMap containing peer names and time to live 18 // used to implement leasing 19 private HashMap peerTTLMap; 20 21 // LeasingThread reference 22 private LeasingThread leasingThread; 23 24 // object that will respond to peer added or removed events 25 private PeerDiscoveryListener peerDiscoveryListener; 26 27 // MulticastSocket for receiving broadcast messages 28 private MulticastSocket multicastSocket; 29 30 // InetAddress of group for messages 31 private InetAddress multicastNetAddress; 32 33 // flag for terminating MulticastReceivingThread 34 privateboolean keepListening = true; 35 Fig. 28.13 Class Multicast-ReceivingThreaduses threads to add and remove peers(part 1).Line 14
Instantiate MulticastSocket to join multicast group Start LeasingThread as deamon thread 36 // MulticastReceivingThread constructor 37 public MulticastReceivingThread( String userName, 38 PeerDiscoveryListener peerEventHandler ) 39 { 40 // invoke superclass constructor to name Thread 41 super( "MulticastReceivingThread" ); 42 43 // set peerDiscoveryListener 44 peerDiscoveryListener = peerEventHandler; 45 46 // connect MulticastSocket to multicast address and port 47 try { 48 multicastSocket = 49 new MulticastSocket( MULTICAST_RECEIVING_PORT ); 50 51 multicastNetAddress = 52 InetAddress.getByName( MULTICAST_ADDRESS ); 53 54 // join multicast group to receive messages 55 multicastSocket.joinGroup( multicastNetAddress ); 56 57 // set 5 second time-out when waiting for new packets 58 multicastSocket.setSoTimeout( 5000 ); 59 } 60 61 // handle exception connecting to multicast address 62 catch( IOException ioException ) { 63 ioException.printStackTrace(); 64 } 65 66 peerTTLMap = new HashMap(); 67 68 // create Leasing thread which decrements TTL of peers 69 leasingThread = new LeasingThread(); 70 leasingThread.setDaemon( true ); Fig. 28.13 Class Multicast-ReceivingThreaduses threads to add and remove peers(part 2).Lines 48-49Lines 69-70
Receive DatagramPacket from MulticastSocket 71 leasingThread.start(); 72 73 } // end MulticastReceivingThread constructor 74 75 // listen for messages from multicast group 76 publicvoid run() 77 { 78 while( keepListening ) { 79 80 // create buffer for incoming message 81 byte[] buffer = newbyte[ MESSAGE_SIZE ]; 82 83 // create DatagramPacket for incoming message 84 DatagramPacket packet = new DatagramPacket( buffer, 85 MESSAGE_SIZE ); 86 87 // receive new DatagramPacket (blocking call) 88 try { 89 multicastSocket.receive( packet ); 90 } 91 92 // handle exception when receive times out 93 catch ( InterruptedIOException interruptedIOException ) { 94 95 // continue to next iteration to keep listening 96 continue; 97 } 98 99 // handle exception reading packet from multicast group 100 catch ( IOException ioException ) { 101 ioException.printStackTrace(); 102 break; 103 } 104 Fig. 28.13 Class Multicast-ReceivingThreaduses threads to add and remove peers(part 3).Lines 84-89