2011-07-27 26 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运行这些示例。 –