Archived

This forum has been archived. Please start a new discussion on GitHub.

Multiple Clients for one Server (Java)

neros
edited February 2018 in Help Center

Could you tell me if its possible to have 3 clients which call methods of a single server ?

«1

Comments

  • mes
    mes California

    Yes, this is possible. Just be aware that the default size for the server-side thread pool is 1, meaning only one request will be dispatched at a time. If you need multiple requests to be dispatched simultaneously, you'll have to increase the maximum size of the server-side thread pool.

  • " meaning only one request will be dispatched at a time " => Only one client can call server methods at the same time ?

  • neros
    edited February 2018

    In fact, I need that during a server method calling, an other client call an other server method to set a class attribute (server class) in order to provide the information needed by the return value of the method called by the first client

  • mes
    mes California
    edited February 2018

    Only one client can call server methods at the same time ?

    Yes, in the default configuration.

    In fact, I need that during a server method calling, an other client call an other server method to set a class attribute (server class) in order to provide the information needed by the return value of the method called by the first client

    In this case you will need to configure the server-side thread pool in the server to have at least two threads:
    Ice.ThreadPool.Server.Size=2

  • Could you tell me where I must set the attribute value ?

  • mes
    mes California

    There are several ways to set configuration properties:

  • neros
    edited March 2018

    Thanks.

    Consequently, by code I must add

    local interface Properties
    {
    void setProperty("Ice.ThreadPool.Server.Size", "2");

    }
    

    in Slice definition ?

  • mes
    mes California

    Not in your Slice definition, this goes in your server code. For example:

    public static void main(String[] args)
    {
        com.zeroc.Ice.InitializationData initData = new com.zeroc.Ice.InitializationData();
        initData.properties = Ice.Util.createProperties(args);
        initData.properties.setProperty("Ice.ThreadPool.Server.Size", "2");
        com.zeroc.Ice.Communicator communicator = Ice.Util.initialize(initData);
        ...
    }
    
  • neros
    edited March 2018
            com.zeroc.Ice.InitializationData initData = new com.zeroc.Ice.InitializationData();
            initData.properties = com.zeroc.Ice.Util.createProperties(args);
            initData.properties.setProperty("Ice.ThreadPool.Server.Size", "2");
    
    
            try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(initData))
            {
    
                com.zeroc.Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("clientmetaserveurAdapter", "default -p 10000");
                com.zeroc.Ice.Object object = new ClientMetaServeurI();
                adapter.add(object, com.zeroc.Ice.Util.stringToIdentity("clientmetaserveur"));
                adapter.activate();
                communicator.waitForShutdown();
            }
    

    is correct ?

  • mes
    mes California

    Yes that looks correct.

  • neros
    edited March 2018

    In the Java Mapping for struct example :

    public final class Employee implements java.lang.Cloneable, java.io.Serializable
    {
    public long number;
    public String firstName;
    public String lastName;

    public Employee() {}
    
    public Employee(long number, String firstName, String lastName)
    {
        this.number = number;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    public boolean equals(java.lang.Object rhs)
    {
        // ...
    }
    public int hashCode()
    {
        // ...
    }
    
    public java.lang.Object clone()
    {
        java.lang.Object o;
        try
        {
            o = super.clone();
        }
        catch(java.lang.CloneNotSupportedException ex)
        {
            assert false; // impossible
        }
        return o;
    }
    

    }

    public boolean equals(java.lang.Object rhs) and public int hashCode() must be empty ?

  • mes
    mes California

    Not sure I understand your question. slice2java does generate code for those methods, we just don't show it in the manual. You can run slice2java and then review the generated code if you want.

  • neros
    edited March 2018

    In fact, I don't need to write myself the java mapping code for struct, it will be automatically generated by slice2java (like String or void types in Slice definition automatically generated...) ?

  • mes
    mes California

    That's correct.

  • neros
    edited March 2018

    Thanks, could you tell me if com.zeroc.Ice.Current current in parameter of a server method not called by the client (used by server himself) is required ?

  • mes
    mes California

    The Ice run time automatically supplies the Current argument to every servant method. Your servant methods must declare this parameter even if you don't use it.

  • An Ice client must be instantiate in a main function, or it can be everywhere... ?

    In fact, One of my ice clients is also an IceStorm Subscriber.

    On Topic message receiving, the client must call an ice server method.

    To do this, I would like to instantiate, use and close an ice client "dynamically" (on some message received contents...)

  • mes
    mes California

    A Communicator represents an instance of the Ice run time. I'm guessing that this is what you mean when you say "ice client". You can create a communicator anywhere, but you also have to ensure the communicator is destroyed. Note that it's not usually necessary for a program to create more than one communicator, and in fact it would be somewhat inefficient to repeatedly create and destroy a communicator every time you needed to make an invocation.

    Take a look at our IceStorm subscriber example. It shows how to implement a subscriber and properly handle the destruction of the communicator.

  • In fact, I'm trying to instantiate an IceClient in a Java Class Constructor, its possible... ?

  • mes
    mes California

    We would need to see some code in order to answer that.

  • neros
    edited March 2018

    Sorry for the delay, I'm very busy with many tasks to do...

    I need that an IceStorm Subscriber send an answer to an Ice Server by creating a temporary Ice Client to call Ice Server methods....

    In order to do that, I think put IceClient in a Java Class and simply crean an object when I need to create a Ice Client to send an answer to Ice Server

    A part of my IceStorm Subscriber code (ClientServeur is the class in which IceClient is coded) :smile:

                          if (m.message.length() > 0) {
                              String[] trame=m.message.split(",");
    
                              if(trame[0].equals("Add")) {
    
                                  if(trame[2].equals("Serveur1")) { this.addMorceau(trame[1], curr); }
    
    
                              } else if(trame[0].equals("Search")) {
    
                                  new ClientServeur(getMorceauByTitre(trame[1], curr));
    
                              } else if(trame[0].equals("Delete")) {
    
                                  this.deleteMorceau(trame[1], curr);
    
                              } else if(trame[0].equals("List")) {
    
                                  new ClientServeur(new String("Serveur1," + this.getListeMorceauxSerialise(curr)));
    
                              } else if(trame[0].equals("Size")) {
    
                                  new ClientServeur(new String("Serveur1," + String.valueOf(this.listeMorceaux.size())));
    
                              } 
    
                          }
    

    ClientServeur class :

    public class ClientServeur {

    public ClientServeur(String message) {
           try(com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(""))
            {
                com.zeroc.Ice.ObjectPrx base = communicator.stringToProxy("clientmetaserveur:default -p 10000");
                MP3.PrinterPrx printer = MP3.PrinterPrx.checkedCast(base);
                if(printer == null)
                {
                    throw new Error("Invalid proxy");
                }
                printer.setReponse(message);
            }
    
    }
    

    }

  • mes
    mes California

    Yes, you can do that. As I wrote earlier, it's not a very efficient strategy because initializing and destroying communicators is relatively expensive. But if this is something you only do occasionally, and it makes the code simpler, then go ahead. In general though, an application typically initializes a communicator once and uses it throughout the program.

  • neros
    edited March 2018

    Thanks, Could you tell me if its possible to share the same servant instance for 3 Ice clients ?

    I have a list in servant class attribute and I need to share the list content with the ice clients (clients will remove, add on the same list...)

  • mes
    mes California

    Yes, that is possible and very common. You should familiarize yourself with the Ice threading model, if you haven't already. By default, there is only one thread in the server-side thread pool, which means only one client request will be processed at a time. You can configure the thread pool with more threads, but then you'll need to use synchronization in the servant.

  • neros
    edited March 2018

    I think that I have a problem.

    In the Ice servant object shared by all Ice clients, a method is blocking until all others client have no answered by calling a method on this servant object...

    while(this.countSubstring("KGmqUPGJpe3DoRteSNPV", this.reponse, current) != this.listeServeurs.size());

    The code is waiting until all client have answered

    Ice can do that... ?

  • mes
    mes California

    If I understand what you're asking, you want a Slice operation to block until the server has received requests from all clients? This is certainly possible, but again it raises threading issues. You'll either need to increase the size of the server-side thread pool so that there are at least as many threads as there are clients, or your servant can use AMD for its implementation.

  • I have an error when I run IceStorm Server :

    threadClientMetaServeur (9) : START
    Exception in thread "threadClientMetaServeur" com.zeroc.Ice.ConnectFailedException
    error = 0
    at com.zeroc.IceInternal.OutgoingAsync.waitForResponseOrUserEx(OutgoingAsync.java:146)
    at com.zeroc.IceInternal.OutgoingAsync.waitForResponse(OutgoingAsync.java:118)
    at com.zeroc.Ice._ObjectPrxI.ice_isA(_ObjectPrxI.java:36)
    at com.zeroc.Ice.ObjectPrx._checkedCast(ObjectPrx.java:862)
    at com.zeroc.Ice.ObjectPrx._checkedCast(ObjectPrx.java:824)
    at com.zeroc.IceStorm.TopicManagerPrx.checkedCast(TopicManagerPrx.java:291)
    at Serveur.MetaServeur$1.run(MetaServeur.java:23)
    at java.lang.Thread.run(Thread.java:748)
    Caused by: java.net.ConnectException: Connexion refusée
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
    at com.zeroc.IceInternal.Network.doFinishConnect(Network.java:541)
    at com.zeroc.IceInternal.StreamSocket.connect(StreamSocket.java:96)
    at com.zeroc.IceInternal.TcpTransceiver.initialize(TcpTransceiver.java:30)
    at com.zeroc.Ice.ConnectionI.initialize(ConnectionI.java:2095)
    at com.zeroc.Ice.ConnectionI.message(ConnectionI.java:1078)
    at com.zeroc.IceInternal.ThreadPool.run(ThreadPool.java:416)
    at com.zeroc.IceInternal.ThreadPool.access$500(ThreadPool.java:12)
    at com.zeroc.IceInternal.ThreadPool$EventHandlerThread.run(ThreadPool.java:785)
    ... 1 more

    Code :

    public static void main(String[] args) throws Exception
    {

            Runnable clientMetaServeurRunnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getId() + ") : START");
    
                        com.zeroc.Ice.Communicator communicator = com.zeroc.Ice.Util.initialize(args);
    
                        com.zeroc.Ice.ObjectPrx obj = communicator.stringToProxy("IceStorm/TopicManager:tcp -p 9999");
                        com.zeroc.IceStorm.TopicManagerPrx topicManager = com.zeroc.IceStorm.TopicManagerPrx.checkedCast(obj);
                        com.zeroc.IceStorm.TopicPrx topic = null;
                        while(topic == null)
                        {
                            try
                            {
                                topic = topicManager.retrieve("MP3");
                            }
                            catch(com.zeroc.IceStorm.NoSuchTopic ex)
                            {
                                try
                                {
                                    topic = topicManager.create("MP3");
                                }
                                catch(com.zeroc.IceStorm.TopicExists ex2)
                                {
                                    // Another client created the topic.
                                }
                            }
                        }
    
                        com.zeroc.Ice.ObjectPrx pub = topic.getPublisher().ice_oneway();
                        MP3.CommunicateurPrx monitor = MP3.CommunicateurPrx.uncheckedCast(pub);
    

    Could you help please ?

  • mes
    mes California

    A "connection refused" error usually means the target server (in this case, IceStorm) is not listening on the host and/or port that was specified in the proxy. Common reasons could be IceStorm isn't running, or IceStorm is listening on a different host/port combination, or the client's proxy is incorrect.

  • I must run another thing that IceStorm Publischer during the same time... ?

  • mes
    mes California

    The IceStorm server is required. It relays messages between publishers and subscribers.