Blokowanie innych poleceń przy uruchomieniu interpretera bash w zdalnym uruchamianiu komend w RMI

0

Mam program na zaliczenie, jednak zaistniał pewien problem, który muszę rozwiązać, otóż mam stworzyć aplikację telnet w RMI, problemem jest fakt, że gdy wydaje polecenie bash powłoka "zawiesza się" i dochodzi do timeoutu, próbowałem wszystkiego i nic, pomógłby ktoś?

import java.rmi.registry.LocateRegistry;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
import java.net.MalformedURLException;
import java.io.*;

public class TelnetServer
    extends UnicastRemoteObject
    implements TelnetInterface
{
    private static String OS = null;
    private static String WindowsShell = "cmd.exe";
    private static String LinuxShell = "/bin/bash";
    String shellCmd;

    /*
     * Zmienne dotyczace procesu powloki
     */

    ProcessBuilder pb = null;
    Process process = null;

    BufferedReader shellReader = null;
    PrintWriter shellWriter = null;

    OutputStream stdin = null;
    InputStream stdout = null;

    public String
    getPlatform ()
    {
        if (OS.startsWith("Windows"))
            return "Windows";
        else
            return "Linux";
    }

    public String
    getShellCommand ()
    {
        if (getPlatform().equals("Windows"))
            return WindowsShell;
        else
            return LinuxShell;
    }

    boolean
    StartShell ()
    {
	try {
	    pb = new ProcessBuilder(shellCmd);
	    pb.redirectErrorStream(true);
	    process = pb.start();

	    stdin = process.getOutputStream(); // <- Eh?
	    stdout = process.getInputStream(); // Na odwrot

	    shellReader = new BufferedReader(new InputStreamReader(stdout));
	    shellWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(stdin)), true);

	    return true;
	} catch(IOException e) {
	    return false;
	}
    } /* StartShell */

    // https://stackoverflow.com/a/3644288
    public String
    ExecuteCommand (String cmd) throws RemoteException
    {
	Print("SV [ExecuteCommand] : " + cmd);
	StringBuffer output = new StringBuffer();

	String input = cmd;
	input = input.trim();

	String line;
	try {
	    shellWriter.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
	    shellWriter.flush();

	    line = shellReader.readLine();
	    while (line != null && ! line.trim().equals("--EOF--")) {
		//System.out.println ("Stdout: " + line);

		if (!line.endsWith("--EOF--")) {
		    output.append(line + "\n");
		}
		line = shellReader.readLine();
	    }
	} catch (Exception e) {
	    Print("Could not execute\"" + cmd + "\"");
	    return "Could not execute\"" + cmd + "\"";
	}

	return output.toString();
    }

    static void
    Print (String s)
    {
	System.out.println(s);
    }

    public
    TelnetServer () throws RemoteException
    {
	OS = System.getProperty("os.name");
        shellCmd = getShellCommand();

	System.out.println("Telnet server running on "
                           + getPlatform()
                           + " with "
                           + shellCmd);
    }

    public static void
    main (String[] args)
    {
	System.setProperty("java.rmi.server.hostname","localhost");
	try {
	    LocateRegistry.createRegistry(1099);
	    TelnetServer sv = new TelnetServer();

	    if (!sv.StartShell()) {
		Print("Nie mozna utworzyc procesu powloki, koniec");
		return;
	    }

	    Naming.rebind("TelnetServer", sv);
	} catch (RemoteException | MalformedURLException e) {
	    Print("Failed to start");
	    e.printStackTrace();
	}
    }
}

Tak PS dało by się do tego dopisać semafory dla more, sort etc?

0

Spróbuj nie opakowywać streama w readera. Jeżeli będziesz czytał bezpośrednio z InputStream, to wtedy masz available, które pozwala ci nie blokować wątku.

A bardziej profesjonalnie to chyba umieścić czytanie z readera w osobnym wątku. Wątek czytający niczego ci nie zablokuje, będzie tylko w kółko przetwarzał to, co odczyta.

1 użytkowników online, w tym zalogowanych: 0, gości: 1