【问题标题】:How to add Pairs to a Java Map如何将对添加到 Java 地图
【发布时间】:2014-04-08 21:20:05
【问题描述】:

这是我在 StackOverflow 上的第一个帖子,所以请耐心等待!

从一个简单的 thrift 服务开始,我想创建一个 java 客户端/服务器应用程序,其中每个节点为分布式计算系统中的其他节点提供一个或多个服务。我想从一个简单的系统开始,其中每个节点都有两个字符串“hostname”和“servicename”,它们相互标识。我创建了这个类:

class NodePort <Node, integer> {
  private Node node;
  private int port;

  NodePort(Node node, int port) {
    this.node = node;
    this.port = port;
  }

  Node getNode() {
    return node;
  }

  int getPort() {
    return port;
  }
}

然后,我编写了一个管理节俭服务,它做了两件事:

1) 向服务器注册一个节点,返回使用的端口

2) 列出当前可用的所有服务

typedef i32 int

struct Node {
  1: string hostName,
  2: string serviceName,
}

service ManagementService {
  int NodeRegister(i32 port)
  Node getNodeForService(Node node)
}

使用 NodeRegister 时,服务器会创建一个 Map,其中键由 serviceNames 给出,值是 NodePorts,并返回客户端使用的端口。

使用 getNodeForService 时,它​​应该返回客户端注册的 Map 中存在的服务列表。

我不确定如何编写这两种方法的实现。我已经写了这个,但是当我尝试测试时它不起作用:

import org.apache.thrift.TException;

import it.uniud.atta.profiling.thrift.ManagementService;

public class ManagementServiceImpl implements ManagementService.Iface {

  public int NodeRegister(int port) throws TException {
    return port;
  }

  public Node getNodeForService(Node node) throws TException {
    return node;
  }
}

我很确定这不会按我想要的方式工作,而且我真的不知道将地图代码放在哪里。我该如何继续?

提前感谢您的帮助!

编辑:我正在添加“用问题回答问题”帖子的内容。不好意思,下次我会好好读规则的!

我实际上需要帮助来编写测试文件。到目前为止,我已经创建了一个监听端口的标准 thrift 服务器和一个 thrift 客户端。代码如下:

public class ManagementServiceTest {

public static class Server implements Runnable {

private TServer tserver;

  public void run() {
      try {
           TServerSocket serverTransport = new TServerSocket(7911);

           ManagementService.Processor<ManagementServiceHandler> processor = new      ManagementService.Processor<ManagementServiceHandler>(new ManagementServiceHandler());

           tserver = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).
                    processor(processor));
           System.out.println("Starting server on port 7911 ...");
           tserver.serve();
          } catch (TTransportException e) {
              e.printStackTrace();
          }
   }

  public void start() {
    new Thread(this).start();
  }

  public void unserve() {
    tserver.stop();
  } 
}

@Test
public void testServerCompletion() {
    Server server = new Server();
    server.start();

    TTransport transport;
    try {

        Thread.sleep(200);
            transport = new TSocket("localhost", 7911);
            TProtocol protocol = new TBinaryProtocol(transport);

            ManagementService.Client client = new ManagementService.Client(protocol);
            transport.open();



//          client.getNodes(testNode.hostName, testNode.serviceName);
//          System.out.println("Servizi disponibili: " + testNode.serviceName);
//            
//          for (String key: nodes.keySet()) {
//
//                System.out.println("key : " + key);
//                System.out.println("value : " + nodes.get(key));            

            transport.close();

            server.unserve();   
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我不确定在 transport.open() 行之后我必须写什么。现在,我应该在端口 7911 上打开一个服务器并进行监听,一个打开的传输和一个需要初始化的未使用的客户端变量。我想使用 RegisterNode() 方法和 getNodes() 方法,但到目前为止我所有的尝试都没有成功。我试过了:

Node node1;
node1 = client.RegisterNode(1025);

但它返回“ManagementService.Client 类型中的方法 RegisterNode(Node, int) 不适用于参数 (String, int)”

所以我尝试了

Node node1;
node1 = client.RegisterNode(node1, 1025);

但它返回“类型不匹配:无法从 int 转换为 Node”。

我还没有尝试过其他方法,但我想我会收到类似的错误。

我不确定我是否了解如何编写测试文件...有什么提示吗?

编辑:好的,我已经设法解决了这个问题:

int port = 0;
Node node1 = new Node();
node1.hostname = "Node 1";
node1.serviceName = "Hello World Service";
port = client.RegisterNode(node1, 1025);
System.out.println("Node hostname: " + node1.hostName + "Node Port Used: " + port);

它确实返回了节点的名称和使用的端口。

现在第二种方法 getNodes() 也存在问题。我正在使用这个:

Nodes nodes = new Nodes();
client.getNodes(node1.hostName, node1.serviceName);
System.out.println("Servizi disponibili: " + node1.serviceName);

for (String key: nodes.keySet()) {

  System.out.println("key : " + key);
  System.out.println("value : " + nodes.get(key));    
}

但它返回两个关于 keySet() 和 get() 方法没有为 tyoe 节点定义的错误。我不确定我应该如何进行...

【问题讨论】:

  • 不起作用”究竟是什么意思?如果每次有人将此作为唯一的错误描述时我得到一美元......那么请:你期望什么,当你尝试什么时会发生什么?
  • 感谢您的回答。Eclipse 在我为测试代码而编写的测试文件中返回错误,在我调用 NodeRegister() 和 getNodeForService() 这两个方法的行中,说未定义 ManagementServiceTest 类型的方法(这是测试文件的名称)。
  • 实际上我已经解决了这个问题,但现在还有另一个问题。我已经编写了一个测试服务器和客户端文件,该文件应该使用端口 1025 使用 serviceName“sum”注册一个名为 node1 的节点。我在使用字符串作为键的 Map 中添加了一个条目(它将是 serviceName,sum),和一个 NodePort 作为值。 Eclipse 告诉我 Map 类型中的 put(String, NodePort) 方法不适用于参数 (Node, int)。我不明白错误在哪里......
  • GetNodes() 返回一个 Nodes 类型(来自下面的 IDL 的结构),其中包含一个成员 allNodes。这个Map&lt;Node,Integer&gt; allNodes 成员其实就是要迭代的map。为什么将其放入结构中更好?一个词:灵活。这样,您可以在以后根据需要扩展返回的数据。
  • 我还建议您查看Thrift Java tutorial 代码。我们真的有一个很好的教程。

标签: java networking client-server thrift


【解决方案1】:

我会以不同的方式构建服务,如下所示:

struct Node {
  1: string hostName,
  2: string serviceName,
}

struct Nodes {
  1: map<Node, i32>  allNodes
}

service ManagementService {
  /** registers a node to a server, returning the port used */
  i32 RegisterNode(1 : Node hostAndService, 2 : i32 preferredPort)

  /** lists all the services available at the moment. 
      Optionally specify host and/or service name to narrow the search */
  Nodes GetNodes(1: string host, 2: string service)
}

地图 代码将在两个服务例程中。在RegisterNode() 中将一个节点添加到地图中,在GetNodes() 中将扫描地图以查找所需的值。

示例代码,未经测试(老实说,甚至没有编译):

public static class ManagementServiceHandler implements ManagementService.Iface {

    private Map<Node,int> nodes;

    public ManagementServiceHandler() 
    {
        nodes = new Map<Node,int>()
    }

    /**
     * registers a node to a server, returning the port used
     */
    public int RegisterNode(Node hostAndService, int preferredPort) {
        int port = preferredPort;
        // TODO: check whether port can be used
        nodes.Add( hostAndService, port);
        return port;    
    }

    /**
     * lists all the services available at the moment.
     * Optionally specify host and/or service name to narrow the search
     */
    public Nodes GetNodes(String host, String svcname)  {
        var Nodes retval = new Nodes();
        retval.allNodes = new Map<Node,int>();

        for( var node : nodes) {
            if( (host.isEmpty() || (host == node.key.host)) {
                if( (svcname.isEmpty() || (svcname == node.key.serviceName)) {
                    retval.allNodes.add(node)
                }
            }
        }

        return retval;
    }
}

【讨论】:

  • 所以 RegisterNode() 的实现类似于: RegisterNode(Node hostAndService, int preferredPort) { Map map = new HashMap; } ?我不确定我应该如何实现 GetNodes()...
  • 感谢您的示例,我正在研究它。不过,我必须检查几件事:1) var 在 java 中不存在,所以我必须删除它并使用完整的类型名称; 2)我不得不用“put”来改变所有的“add”)。此外,某个地方存在问题,因为eclipse一直告诉我“类型ManagementServiceHandler必须实现继承的抽象方法ManagementService.Iface.getNodes(String,String)”,但该方法存在。一种解决方案是使 ManagementServiceHandler 抽象,另一种方法是创建返回 null 的 getNodes() 方法。在我看来,两者都是错误的。我该怎么办?
  • 发现问题了,只是方法名不对(GetNodes 而不是getNodes)。现在我必须研究迭代器,因为它根据 eclipse 有一些问题...... 1)“键无法解析或不是字段”和 2)“只能迭代数组或 java.lang 的实例.Iterable” 在 for 行“for(Nodes node : nodes)”。我需要在那里改变一些东西。无论如何,非常感谢您的帮助!
  • 您可以随时提问、投票或接受 ;-)
猜你喜欢
  • 2020-12-23
  • 2016-07-01
  • 2018-02-22
  • 2011-11-25
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
  • 2014-08-21
相关资源
最近更新 更多