【问题标题】:Jini/JavaSpaces discovery errorJini/JavaSpaces 发现错误
【发布时间】:2011-07-27 22:24:17
【问题描述】:

在这篇文章中:http://java.sun.com/developer/technicalArticles/tools/JavaSpaces/ 是一个如何运行 JavaSpaces 客户端的教程。我在 Eclipse 中编写了这些类,启动了 Launch-All 脚本和运行示例。有用。 之后,我将这些类导出到可执行 jar (JavaSpaceClient.jar) 中,并使用以下命令尝试了该 jar: java -jar JavaSpaceClient.jar 它工作正常,给了我结果: 正在搜索 JavaSpace... 已发现一个 JavaSpace。 向空间写入消息... 从空间读取消息... 读取的消息是:Здраво JavaSpace свете!

我的问题是当我在我的另一台 LAN 计算机上移动这个 jar 文件时,当我输入相同的命令时它显示错误。这是错误:

cica@cica-System-Name:~/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...”,过了一会儿打印了这些错误消息。 有人可以帮我解决这个错误吗?

编辑: 对于发现,我正在使用我在 Internet 上找到的 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 (dan@dancres.org)
   @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;
   }
}

编辑2: 我在两台 Windows 计算机上进行了发现。 之后我尝试了 Windows - Ubuntu 组合,但它不起作用。也许有一些网络问题?当我互相ping通时,一切正常。也许在 Ubuntu 上有一些 DNS 问题..

编辑3: Windows - 如果 JavaSpaces 服务在 Windows 上启动并且客户端程序在 Ubuntu 上,则 Ubuntu 组合可以工作。当我尝试进行反向操作时,在 Ubuntu 上运行 JavaSpaces 服务并在 Windows 上运行客户端会发生错误。 显然 Ubuntu 存在一些问题。 Ubuntu 已经安装了默认安装的 OpenJDK。我安装了 Oracle JDK,并设置了 JAVA_HOME 并将 JAVA_HOME/bin 放入 PATH 变量中。我想知道不同版本的 Java 可能存在一些问题,也许我没有使用正确的版本。

【问题讨论】:

    标签: java distributed-computing javaspaces jini


    【解决方案1】:

    您正在运行的服务注册器(在主机 biske-Inspiron-1525 的端口 4160 上)可能发现它的主机名不正确(没有域名),因此发送带有短主机名的通知。因此,在发现服务注册器之后,客户端可能随后尝试与服务注册器建立连接,如果它位于不同的域中,它无法解析主机名。

    要确保服务注册器使用正确的主机名运行,请尝试使用以下命令行属性启动它:

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

    【讨论】:

    • 我用这个选项开始 reggie,但 JavaSpaceClient 打印出“正在寻找 JavaSpace...”,但没有任何反应。我正在使用 Apache River 运行这些示例。
    【解决方案2】:

    您似乎正在对特定主机和端口进行单播发现,并且您无法查找该主机。

    假设您可以使用 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
    }
    

    【讨论】:

    • 感谢没有多少人可以帮助 JavaSpaces,感谢您的帮助。我编辑了我的问题,你能建议我改变什么吗?
    • 刚刚看到你正在使用的发现代码。看起来您正在使用多播发现,但是当它找到主机时出现问题。试试@beny23 说的。还可以尝试使用机器的 IP 地址而不是主机名指定单播发现,以确保不存在某种 DNS 问题。
    • 我想在您的课程中尝试我的 Hello World 示例,但 Eclipse 告诉我 TheService 无法解析为类型。你说应该是接口,这个接口在哪里找?
    • 将 serviceClasses 数组中的 TheService.class 替换为 JavaSpace.class。这将查找实现 JavaSpace 接口的服务,该接口是您在编写和读取 MessageEntry 对象时使用的。
    • 我确实像你说的那样,但现在我有上帝的例外:警告,使用默认的多播发现。 java.security.AccessControlException:在 java.lang 的 java.security.AccessController.checkPermission(AccessController.java:553) 的 java.security.AccessControlContext.checkPermission(AccessControlContext.java:393) 的访问被拒绝 (java.security.SecurityPermission getPolicy) .SecurityManager.checkPermission(SecurityManager.java:549) at java.security.Policy.getPolicy(Policy.java:151) at net.jini.security.Security$7.run(Security.java:781)
    【解决方案3】:

    我找到了解决方案!那是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 行,现在它可以正常工作了。 小东西摧毁了我的百万神经:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      • 2012-08-05
      • 2017-11-18
      • 2013-02-27
      相关资源
      最近更新 更多