2015-12-03 3 views
1

Я кодирую сценарий Julia с ZeroMQ.
выполнить julia скрипты из Java

Моя цель - связаться с ZMQ между двумя сценариями. Вот пример:

# 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) 

Я могу выполнять их с Юлей в командной строке. Все идет хорошо. Сценарий 2 может получить сообщение сценария 1.

Теперь мне нужно выполнить их с Java. Это означает, что мне нужно создать проект java, который похож на контроллер. Вот мой 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(); 
    } 
} 

Однако, когда я бег моего проекта Java, я могу видеть, что она продолжает работать, но я ничего не вижу на консоли: нет результата, нет сообщений, ошибок нет.

Я думаю, что что-то не так в моем проекте java.

+0

Вы 'p.waitFor()', который будет ждать завершения процесса. Таким образом, ваш второй скрипт запускается только при завершении первого. – Kenney

+0

@ Kenney Итак, я должен удалить это 'if' или что? Я не совсем понимаю, как захватить поток исполняемого файла из проекта java. – Yves

ответ

1

Вы должны одновременно запускать два сценария: script2 - это серверный скрипт, поэтому он должен запускаться при запуске script1. Как и сейчас, Process.waitFor() будет ждать script1, клиентского скрипта, чтобы завершить, перед выполнением сценария сервера script2 в следующей итерации for.

Вы могли бы начать их как таковые:

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); 

и два экземпляра темы, читать их выходы:

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

использованием

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(); 
     } 
    } 
} 

Хотя, так как clientScript не производят любой вывод, вы можете просто запустить скрипты, nd считывает только выходные данные из сценария сервера - нет необходимости в потоке.

Есть еще одна вещь, которую следует учитывать: serverScript должен быть listening... перед попытками подключения clientScript. Поэтому вы можете это сделать:

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

Большое спасибо. Btw, ZMQ может содержать сообщение, отправленное с его собственным потоком, даже если приемник там не был. В этом случае мы не можем закрыть контекст ZMQ, но нам не нужно убеждаться, что сервер должен быть выполнен до выполнения клиента. – Yves