2011-07-27 23 views
0

本文內容:http://java.sun.com/developer/technicalArticles/tools/JavaSpaces/是一篇如何運行JavaSpaces客戶端的教程。我在Eclipse中編寫了這些類,啓動了Launch-All腳本和Run示例。有用。 之後,我將這些類導出到可執行jar(JavaSpaceClient.jar)中,並使用以下命令嘗試了該jar: java -jar JavaSpaceClient.jar 工作正常,結果爲: 正在搜索JavaSpace ... JavaSpace已被發現。 將消息寫入空間... 從空間讀取消息... 讀取的消息是:ЗдравоJavaSpaceсвете!Jini/JavaSpaces發現錯誤

我的問題是,當我移動我的其他LAN計算機上的這個jar文件時,它顯示我輸入相同的命令時出錯。下面是錯誤:

[email protected]:~/Desktop$ java -jar JavaSpaceClient.jar 
Searching for a JavaSpace... 
Jul 27, 2011 11:20:54 PM net.jini.discovery.LookupDiscovery$UnicastDiscoveryTask run 
INFO: exception occurred during unicast discovery to biske-Inspiron-1525:4160 with constraints InvocationConstraints[reqs: {}, prefs: {}] 
java.net.UnknownHostException: biske-Inspiron-1525 
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:175) 
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:384) 
at java.net.Socket.connect(Socket.java:546) 
at java.net.Socket.connect(Socket.java:495) 
at com.sun.jini.discovery.internal.MultiIPDiscovery.getSingleResponse(MultiIPDiscovery.java:134) 
at com.sun.jini.discovery.internal.MultiIPDiscovery.getResponse(MultiIPDiscovery.java:75) 
at net.jini.discovery.LookupDiscovery$UnicastDiscoveryTask.run(LookupDiscovery.java:1756) 
at net.jini.discovery.LookupDiscovery$DecodeAnnouncementTask.run(LookupDiscovery.java:1599) 
at com.sun.jini.thread.TaskManager$TaskThread.run(TaskManager.java:331) 

我只是寫道:「在搜索JavaSpace ......」過了一會打印這些錯誤消息。 有人可以幫我解決這個錯誤嗎?

編輯: 對於發現我使用LookupDiscovery類,我在網上查到:

import java.io.IOException; 

import java.rmi.RemoteException; 

import net.jini.core.lookup.ServiceRegistrar; 
import net.jini.core.lookup.ServiceTemplate; 

import net.jini.discovery.LookupDiscovery; 
import net.jini.discovery.DiscoveryListener; 
import net.jini.discovery.DiscoveryEvent; 

/** 
    A class which supports a simple JINI multicast lookup. It doesn't register 
    with any ServiceRegistrars it simply interrogates each one that's 
    discovered for a ServiceItem associated with the passed interface class. 
    i.e. The service needs to already have registered because we won't notice 
    new arrivals. [ServiceRegistrar is the interface implemented by JINI 
    lookup services]. 

    @todo Be more dynamic in our lookups - see above 

    @author Dan Creswell ([email protected]) 
    @version 1.00, 7/9/2003 
*/ 
public class Lookup implements DiscoveryListener { 
    private ServiceTemplate theTemplate; 
    private LookupDiscovery theDiscoverer; 

    private Object theProxy; 

    /** 
     @param aServiceInterface the class of the type of service you are 
     looking for. Class is usually an interface class. 
    */ 
    public Lookup(Class aServiceInterface) { 
     Class[] myServiceTypes = new Class[] {aServiceInterface}; 
     theTemplate = new ServiceTemplate(null, myServiceTypes, null); 
    } 

    /** 
     Having created a Lookup (which means it now knows what type of service 
     you require), invoke this method to attempt to locate a service 
     of that type. The result should be cast to the interface of the 
     service you originally specified to the constructor. 

     @return proxy for the service type you requested - could be an rmi 
     stub or an intelligent proxy. 
    */ 
    Object getService() { 
     synchronized(this) { 
      if (theDiscoverer == null) { 

       try { 
        theDiscoverer = 
         new LookupDiscovery(LookupDiscovery.ALL_GROUPS); 
        theDiscoverer.addDiscoveryListener(this); 
       } catch (IOException anIOE) { 
        System.err.println("Failed to init lookup"); 
        anIOE.printStackTrace(System.err); 
       } 
      } 
     } 

     return waitForProxy(); 
    } 

    /** 
     Location of a service causes the creation of some threads. Call this 
     method to shut those threads down either before exiting or after a 
     proxy has been returned from getService(). 
    */ 
    void terminate() { 
     synchronized(this) { 
      if (theDiscoverer != null) 
       theDiscoverer.terminate(); 
     } 
    } 

    /** 
     Caller of getService ends up here, blocked until we find a proxy. 

     @return the newly downloaded proxy 
    */ 
    private Object waitForProxy() { 
     synchronized(this) { 
      while (theProxy == null) { 

       try { 
        wait(); 
       } catch (InterruptedException anIE) { 
       } 
      } 

      return theProxy; 
     } 
    } 

    /** 
     Invoked to inform a blocked client waiting in waitForProxy that 
     one is now available. 

     @param aProxy the newly downloaded proxy 
    */ 
    private void signalGotProxy(Object aProxy) { 
     synchronized(this) { 
      if (theProxy == null) { 
       theProxy = aProxy; 
       notify(); 
      } 
     } 
    } 

    /** 
     Everytime a new ServiceRegistrar is found, we will be called back on 
     this interface with a reference to it. We then ask it for a service 
     instance of the type specified in our constructor. 
    */ 
    public void discovered(DiscoveryEvent anEvent) { 
     synchronized(this) { 
      if (theProxy != null) 
       return; 
     } 

     ServiceRegistrar[] myRegs = anEvent.getRegistrars(); 

     for (int i = 0; i < myRegs.length; i++) { 
      ServiceRegistrar myReg = myRegs[i]; 

      Object myProxy = null; 

      try { 
       myProxy = myReg.lookup(theTemplate); 

       if (myProxy != null) { 
        signalGotProxy(myProxy); 
        break; 
       } 
      } catch (RemoteException anRE) { 
       System.err.println("ServiceRegistrar barfed"); 
       anRE.printStackTrace(System.err); 
      } 
     } 
    } 

    /** 
     When a ServiceRegistrar "disappears" due to network partition etc. 
     we will be advised via a call to this method - as we only care about 
     new ServiceRegistrars, we do nothing here. 
    */ 
    public void discarded(DiscoveryEvent anEvent) { 
    } 
} 

我的客戶端程序試圖簡單地搜索JavaSpaces的服務寫MessageEntry進入之後,獲取信息並打印出來。下面是客戶端程序:

import net.jini.space.JavaSpace; 

public class SpaceClient { 
    public static void main(String argv[]) { 
     try { 
     MessageEntry msg = new MessageEntry(); 
     msg.content = "Hello JavaSpaces wordls!"; 
     System.out.println("Searching for JavaSpaces..."); 
     Lookup finder = new Lookup(JavaSpace.class); 
     JavaSpace space = (JavaSpace) finder.getService(); 
     System.out.println("JavaSpaces discovered."); 
     System.out.println("Writing into JavaSpaces..."); 
     space.write(msg, null, 60*60*1000); 
     MessageEntry template = new MessageEntry(); 
     System.out.println("Reading message from JavaSpaces..."); 
     MessageEntry result = (MessageEntry) space.read(template, null, Long.MAX_VALUE); 
     System.out.println("Message: "+result.content); 
     } catch(Exception e) { 
     e.printStackTrace(); 
     } 
    } 
} 

當然,這並是MessageEntry類:

import net.jini.core.entry.*; 

public class MessageEntry implements Entry { 
    public String content; 

    public MessageEntry() { 
    } 

    public MessageEntry(String content) { 
    this.content = content; 
    } 

    public String toString() { 
    return "MessageContent: " + content; 
    } 
} 

EDIT2: 我沒有發現兩個Windows計算機。 之後,我嘗試Windows - Ubuntu combiantion,它不起作用。也許有一些網絡問題?當我互相ping通時,一切都很好。也許在Ubuntu上有一些DNS問題..

EDIT3: Windows - 如果JavaSpaces服務在Windows上啓動並且客戶端程序在Ubuntu上,則Ubuntu組合可以工作。當我嘗試做相反的事情時,在Ubuntu上運行JavaSpaces服務並在Windows上運行客戶端時發生錯誤。 顯然Ubuntu有一些問題。 Ubuntu默認安裝了OpenJDK。我安裝了Oracle JDK,並設置了JAVA_HOME並將JAVA_HOME/bin放入了PATH變量。不知道Java版本可能存在一些問題,也許我沒有使用正確的版本。

回答

0

我找到了解決方案!這是DNS問題。在Ubuntu上我的/ etc/hosts文件是:

192.168.1.3 biske-Inspiron-1525 # Added by NetworkManager 
127.0.0.1 localhost.localdomain localhost 
::1 biske-Inspiron-1525 localhost6.localdomain6 localhost6 
127.0.1.1 biske-Inspiron-1525 

# The following lines are desirable for IPv6 capable hosts 
::1  localhost ip6-localhost ip6-loopback 
fe00::0 ip6-localnet 
ff00::0 ip6-mcastprefix 
ff02::1 ip6-allnodes 
ff02::2 ip6-allrouters 
ff02::3 ip6-allhosts 

我剛剛刪除線127.0.1.1 biske-的Inspiron - 1525,現在它工作正常。 小東西被毀了我的神經萬分:)

1

看來您正在對特定主機和端口執行單播發現,並且您無法查找該主機。

假設您可以使用DNS解析名稱biske-Inspiron-1525,請嘗試刪除「:4160」部分,然後查看單播查找是否成功。

以下是我用來查找服務的代碼示例。這有點複雜,因爲我實現了ServiceDiscoveryListener並以這種方式處理服務發現。我實際上保留了一個服務列表,然後在出現故障時動態切換,但是我將該部分從示例中剝離出來。我也在使用Jini的配置部分,我將在後面解釋。我使用這裏的服務接口被稱爲「TheService」:

public class JiniClient implements ServiceDiscoveryListener { 

private TheService service = null; 

private Class[] serviceClasses; 
private ServiceTemplate serviceTemplate; 

public JiniClient(String[] configFiles) throws ConfigurationException { 

    Configuration config = ConfigurationProvider.getInstance(configFiles, 
      getClass().getClassLoader()); 


    // Set the security manager 
    System.setSecurityManager(new RMISecurityManager());   

    // Define the service we are interested in. 
    serviceClasses = new Class[] {TheService.class}; 
    serviceTemplate = new ServiceTemplate(null, serviceClasses, null); 

    // Build a cache of all discovered services and monitor changes 
    ServiceDiscoveryManager serviceMgr = null; 

    DiscoveryManagement mgr = null; 
    try { 
     mgr = (DiscoveryManagement)config.getEntry(
       getClass().getName(), // component 
       "discoveryManager",     // name 
       DiscoveryManagement.class);   // type 

     if (null == mgr) { 
      throw new ConfigurationException("entry for component " + 
        getClass().getName() + " name " + 
        "discoveryManager must be non-null"); 
     } 
    } catch (Exception e) { 
     /* This will catch both NoSuchEntryException and 
     * ConfigurationException. Putting them both 
     * below just to make that clear. 
     */ 
     if((e instanceof NoSuchEntryException) || 
       (e instanceof ConfigurationException)) { 
      // default value 
      try { 
       System.err.println("Warning, using default multicast discover."); 
       mgr = new LookupDiscoveryManager(LookupDiscovery.ALL_GROUPS, 
         null, // unicast locators 
         null); // DiscoveryListener 
      } catch(IOException ioe) { 
       e.printStackTrace(); 
     throw new RuntimeException("Unable to create lookup discovery manager: " + e.toString()); 
      } 
     } 
    } 

    try { 
     serviceMgr = new ServiceDiscoveryManager(mgr, new LeaseRenewalManager()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     throw new RuntimeException("Unable to create service discovery manager: " + e.toString()); 
    } 

    try { 
     serviceMgr.createLookupCache(serviceTemplate, 
               null, // no filter 
               this); // listener 
    } catch(Exception e) { 
     e.printStackTrace(); 
     throw new RuntimeException("Unable to create serviceCache: " + e.getMessage()); 
    } 
} 

public void serviceAdded(ServiceDiscoveryEvent evt) { 
     /* Called when a service is discovered */ 
    ServiceItem postItem = evt.getPostEventServiceItem(); 
    //System.out.println("Service appeared: " + 
    //   postItem.service.getClass().toString()); 

    if(postItem.service instanceof TheService) { 
     /* You may be looking for multiple services. 
        * The serviceAdded method will be called for each 
        * so you can use instanceof to figure out if 
        * this is the one you want. 
        */ 
     service = (TheService)postItem.service; 

    }  
} 

public void serviceRemoved(ServiceDiscoveryEvent evt) { 
/* This notifies you of when a service goes away. 
    * You could keep a list of services and then remove this 
    * service from the list. 
*/ 
} 

public void serviceChanged(ServiceDiscoveryEvent evt) { 
/* Likewise, this is called when a service changes in some way. */ 

} 

配置系統允許你動態配置發現方法,這樣就可以切換到發現特定的單播系統或多播無需改變應用程序。這是,你可以通過以上對象構造一個單播發現配置文件的例子:

import net.jini.core.discovery.LookupLocator; 
import net.jini.discovery.LookupDiscoveryManager; 
import net.jini.discovery.LookupDiscovery; 

com.company.JiniClient { 
    discoveryManager = new LookupDiscoveryManager(
     LookupDiscovery.ALL_GROUPS, 
     new LookupLocator[] { new LookupLocator("jini://biske-Inspiron-1525.mycompany.com")}, 
     null, 
     this); // the current config 
} 
+0

感謝沒有太多的人來幫助JavaSpaces,我感謝您的幫助。我編輯了我的問題,你能告訴我要改變什麼嗎? –

+0

使用示例代碼更新了我的回覆。 –

+0

剛剛看到您正在使用的發現代碼。看起來您正在使用多點傳送發現,但發現主機時發生錯誤。試試@ beny23說的。另外,請嘗試使用您的計算機的IP地址而不是主機名來指定單播發現,以確保沒有某種DNS問題。 –

2

這是可能的,你是(在端口4160上的主機biske-的Inspiron-1525)上運行的服務註冊,發現它的主機名是錯誤的(沒有域名),因此用簡短的主機名發出通知。因此,在發現服務註冊機構後,客戶機可能會嘗試與服務註冊機構建立連接,但如果它位於不同的域上,則無法解析主機名。

爲了保證服務註冊與正確的主機上運行,​​嘗試用以下命令行屬性啓動它:

-Dcom.sun.jini.reggie.unicastDiscoveryHost="biske-Inspiron-1525.and.its.domain" 
+0

我用這個選項啓動了reggie,但是JavaSpaceClient輸出「Looking for JavaSpace ...」並沒有任何反應。我正在使用Apache River運行這些示例。 –