2015-12-03 1 views
1

Je suis en train de coder le script Julia avec ZeroMQ.
exécuter des scripts julia à partir de Java

Mon but est de communiquer avec ZMQ entre deux scripts. Voici un exemple:

# script1 
using ZMQ 
ctx = ZMQ.Context() 
sockDealer = ZMQ.Socket(ctx, DEALER) 
ZMQ.set_identity(sockDealer, "idA") 
ZMQ.connect(sockDealer, "tcp://localhost:5555") 
ZMQ.send(sockDealer, "hello world!") 
ZMQ.close(sockDealer) 
ZMQ.close(ctx) 



#script2 
using ZMQ 

function pollrecv(socket::ZMQ.Socket,zmsg::Message) 
    rc = -1 
    while true 
    rc = ccall((:zmq_msg_recv, ZMQ.zmq), Cint, (Ptr{Message}, Ptr{Void}, Cint), 
        &zmsg, socket.data, ZMQ.ZMQ_DONTWAIT) 
    if rc == -1 
    # Base.Libc.EAGAIN = 11 
    # Problem unsolved: Failure to find Base.Libc.EAGAIN 
    if !(ZMQ.zmq_errno() == 11) 
     throw(ZMQ.StateError(ZMQ.jl_zmq_error_str())) 
    end 
    return false 
    else 
     ZMQ.get_events(socket) != 0 && notify(socket) 
     break 
    end 
    end 
    return true 
end 

ctx = ZMQ.Context() 
sockRouter = ZMQ.Socket(ctx, ROUTER) 
ZMQ.bind(sockRouter, "tcp://*:5555") 
fini = false 
while !fini 
    println("listening...") 
    idSock = Message() 
    while pollrecv(sockRouter, idSock) 
    msg = ZMQ.recv(sockRouter) 
    println("msg recv: " * bytestring(msg)) 
    fini = true 
    end 
    sleep(1) 
end 
ZMQ.close(sockRouter) 
ZMQ.close(ctx) 

Je peux les exécuter avec Julia sur l'invite de commande. Tout va bien. Le script 2 peut recevoir le message du script 1.

Maintenant, j'ai besoin de les exécuter depuis Java. Ce qui signifie que j'ai besoin de créer un projet Java qui est comme un contrôleur. Voici mon projet Java:

public class Container { 

    private Vector<String[]> commands; 

    public Container() { 
     this.commands = new Vector<String[]>(); 
    } 

    public void addCommand(String[] strs) { 
     this.commands.addElement(strs); 
    } 

    public void execute() { 
     for(int i = 0; i < this.commands.size(); i++) { 
      try { 
       Process p = Runtime.getRuntime().exec(this.commands.get(i)); 
       if(p.waitFor() != 0){ 
        System.err.println("exit value = " + p.exitValue()); 
       } 
       BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); 
       StringBuffer stringBuffer = new StringBuffer(); 
       String line = null; 
       while((line = in.readLine()) != null){ 
        stringBuffer.append(line + "-"); 
       } 
       System.out.println(stringBuffer.toString()); 

      } catch (IOException ex) { 
       // TODO Auto-generated catch block 
       ex.printStackTrace(); 
      } catch(InterruptedException e){ 
       System.err.println(e); 
      } 
     } 
    } 
} 


//main 
public class Main { 
    public static void main(String[] args) { 
     Container c = new Container(); 

     String[] script1 = {"/usr/bin/julia", "/home/thomas/Julia/script1.jl"}; 
     String[] script2 = {"/usr/bin/julia", "/home/thomas/Julia/script2.jl"}; 
     c.addCommand(script1); 
     c.addCommand(script2); 
     c.execute(); 
    } 
} 

Cependant, quand je lance mon projet java, je peux voir qu'il continue à fonctionner, mais je ne vois rien sur la console: aucun résultat, aucun message, aucune erreur.

Je pense qu'il y a quelque chose qui ne va pas dans mon projet java.

+0

Vous 'p.waitFor()', qui attendra que le processus se termine. Ainsi, votre deuxième script ne sera exécuté que lorsque le premier sera terminé. – Kenney

+0

@Kenney Donc, je devrais enlever ce 'si 'ou quoi? Je ne comprends pas très bien comment capturer le flux sortant d'un fichier exécutable d'un projet Java. – Yves

Répondre

1

Vous devez exécuter les deux scripts simultanément: script2 est le script du serveur, il doit donc être en cours d'exécution lorsque vous exécutez script1. Comme il est maintenant, Process.waitFor() attend script1, le script client, pour terminer, avant d'exécuter le script serveur script2 dans l'itération suivante for.

Vous pouvez les aider en tant que tel:

String[] clientScript = { "/usr/bin/julia", "/home/thomas/Julia/script1.jl" }; 
    String[] serverScript = { "/usr/bin/julia", "/home/thomas/Julia/script2.jl" }; 

    Process server = Runtime.getRuntime().exec(serverScript); 
    Process client = Runtime.getRuntime().exec(clientScript); 

et instancier deux fils pour lire leurs sorties:

(new ProcessReader(server)).start(); 
    (new ProcessReader(client)).start(); 

utilisant

public class ProcessReader extends Thread { 
    private Process p; 

    public ProcessReader(Process p) { 
     this.p = p; 
    } 

    @Override 
    public void run() { 
     BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); 
     try { 
      String line; 
      while ((line = in.readLine()) != null) { 
       System.out.println("Read: " + line); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Bien que, depuis le clientScript ne le fait pas produire toute sortie, vous pouvez simplement commencer les scripts, et seulement lire la sortie du script du serveur - pas de thread nécessaire.

Il y a encore une chose à considérer: le serverScript doit être listening... avant que le clientScript ne tente de se connecter. Donc, vous voudrez peut-être faire ceci:

Process server = Runtime.getRuntime().exec(serverScript); 
    BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream())); 
    if (in.readLine().equals("listening...")) { 
     Process client = Runtime.getRuntime().exec(clientScript); 

     String line; 
     while ((line=in.readLine()) != null) 
      System.out.println("Read: " + line); 
    } 
+0

Merci beaucoup. Btw, ZMQ peut contenir le message envoyé avec son propre fil même si le récepteur n'a pas été là. Dans ce cas, nous ne pouvons pas fermer le contexte de ZMQ mais nous n'avons pas besoin de nous assurer que le serveur doit être exécuté avant l'exécution du client. – Yves