I have an IRC bot which hosts game servers given a few arguments. The problem is, once it hosts a server, it stops listening to IRC (meaning realistically, only one server can be hosted at a time). This is not what I want.
I assumed threading would be the answer to my problem, but I can't seem to get it to work. It appears that it doesn't actually start in another thread?
Here is my main class which starts and runs the method via threading:
// Everything is okay, run the server.
Runnable r = new Server(this, channel);
Thread thread = new Thread(r);
thread.start();
And here is the Server class which (presumably) controls the threading:
public class Server extends PircBot implements Runnable {
public void run() {
}
public Server (bot BotRun, String channel) {
String names[] = org.bestever.bebot.bot.hostbuilder.split(" ");
ProcessBuilder pb = new ProcessBuilder(names);
pb.redirectErrorStream(true);
try {
Process proc = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLine = null;
while((strLine = br.readLine()) != null) {
// Returns UDP Initialized if the server was successfully started
if (strLine.equalsIgnoreCase("UDP Initialized.")) {
BotRun.sendMessage(channel, "Server started successfully.");
}
// Returns Bad Hex Number if there is a problem with the WAD file
else if (strLine.startsWith("Bad hex number")) {
BotRun.sendMessage(channel, "Error starting server: "+strLine);
}
System.out.println(strLine);
}
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
Have I not actually started it in a thread? Thanks for any help!
I am afraid, not.
Server class should be more like:
public class Server extends PircBot implements Runnable {
private bot BotRun;
private String channel;
public void run() {
String names[] = org.bestever.bebot.bot.hostbuilder.split(" ");
ProcessBuilder pb = new ProcessBuilder(names);
pb.redirectErrorStream(true);
try {
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLine = null;
while((strLine = br.readLine()) != null) {
// Returns UDP Initialized if the server was successfully started
if (strLine.equalsIgnoreCase("UDP Initialized.")) {
BotRun.sendMessage(channel, "Server started successfully.");
}
// Returns Bad Hex Number if there is a problem with the WAD file
else if (strLine.startsWith("Bad hex number")) {
BotRun.sendMessage(channel, "Error starting server: "+strLine);
}
System.out.println(strLine);
}
reader.close();
Thread.currentThread().interrupt();
} catch (IOException e) {
e.printStackTrace();
}
}
public Server (bot BotRun, String channel) {
this.BotRun = BotRun;
this.channel = channel;
}
}
Your run() method is empty; it starts, does nothing, and ends.
Related
I made a client-server application where the server has to send a list of emails to the client, which after load that into a ListView gives the possibility, through a menuBar, to delete them. In the client all these operations are made in the Data Model (I followed the MVC pattern). This is the server:
class ThreadedEchoHandler implements Runnable {
private Socket incoming;
private String nomeAccount = "";
public void run() {
try {
incoming = s.accept();
} catch (IOException ex) {
System.out.println("Unable to accept requests");
}
contenutoTextArea.append("Connected from: " + incoming.getLocalAddress() + "\n");
textarea.setText(contenutoTextArea.toString());
try {
//PHASE 1: The server receives the email
try {
BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
nomeAccount = in.readLine();
} catch (IOException ex) {
System.out.println("Not works");
}
//PHASE 2: I'm getting all the emails from the files
File dir = new File("src/server/" + nomeAccount);
String[] tmp = new String[100];
int i = 0;
for (File file : dir.listFiles()) {
if (file.isFile() && !(file.getName().equals(".DS_Store"))) {
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
tmp[i++] = line;
}
} catch (IOException ex) {
System.out.println("Cannot read from file");
}
}
}
//PHASE 3: The server sends the ArrayList to the client
PrintWriter out = new PrintWriter(incoming.getOutputStream(), true);
for (int j = 0; j < i; j++) {
out.println(tmp[j]); // send the strings to the client
}
} catch (IOException ex) {
System.out.println("Cannot send the strings to the client");
}
//PHASE 4: Here I loop and wait for the client choise
BufferedReader in;
String op;
try {
in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
while ((op = in.readLine()) != null) {
if (op.equals("Elimina")) {
String tmp = in.readLine();
File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
file.delete();
} else if (op.equals("Invia")) {
//...
} else {
//...
}
}
} catch (IOException ex) {
System.out.println("Non so");
} finally {
try {
incoming.close();
} catch (IOException ex) {
System.out.println("Cannot closing the socket");
}
}
}
}
These are the methods of the client:
public void loadData() throws IOException, ClassNotFoundException, ParseException {
try {
s = new Socket("127.0.0.1", 5000);
ArrayList<Email> email = new ArrayList<Email>();
DateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date data;
/* PHASE 1: The client sends a string to the server */
//try {
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println(account); // send the account name to server
/* PHASE 2: The client receives the ArrayList with the emails */
BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line;
String message[] = new String[5];
for (int j=0; (line = in.readLine()) != null;) {
message[j++] = line;
if (j==5) {
data = format.parse(message[3]);
email.add(new Email((Integer.parseInt(message[0])), message[1], account, message[2], message[4], data));
j=0;
}
}
//Casting the arrayList
emailList = FXCollections.observableArrayList(email);
//Sorting the emails
Collections.sort(emailList, (Email o1, Email o2) -> {
if (o1.getData() == null || o2.getData() == null) {
return 0;
}
return o1.getData().compareTo(o2.getData());
});
/*} finally {
s.close();*/
//}
} catch (SocketException se) {
emailList.setAll(null, null);
}
}
public void deleteMail(Email da_elim) throws IOException {
int id_del = da_elim.getID();
emailList.remove(da_elim);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("Elimina");
out.println(id_del);
}
The PHASE 1, 2, 3 of the Server are for the upload of the emails, and work with the loadData() method. Without the PHASE 4 the program works. Now, if I write that loop, the GUI of the client doesn't load and I cannot press on the DELETE button (which should make the input to innescate something (in this the elimination of the file) into that loop. Why the client doesn't load even if they are two different threads? And why without that loop it works?
EDIT: with the Listener class implemented but still doesn't works
//PHASE 4: Here I loop and wait for the client choise
BufferedReader in;
String op;
try {
in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
/*while ((op = in.readLine()) != null) {
System.out.println("OP: " + op);
if (op.equals("Elimina")) {
String tmp = in.readLine();
contenutoTextArea.append("Ho eliminato la mail ").append(tmp).append(" \n");
textarea.setText(contenutoTextArea.toString());
File file = new File("src/server/" + nomeAccount + "/" + tmp + ".txt");
file.delete();
}
}*/
Listener lis = new Listener(in, new LinkedBlockingQueue<String>());
lis.run();
System.out.println("bbbbb");
} catch (IOException ex) {
System.out.println("Unable to read messages");
} finally {
try {
incoming.close();
} catch (IOException ex) {
System.out.println("Cannot close the socket");
}
}
I think you should run jvisualvm (it's a tool installed with jdk in /bin/ location of your jdk) and look for that Thread lifecycle you create on server. Also check if your Thread don't go through the code and just ends his life skipping waiting for client.
Is this Thread somehow connected with client? Because you cannot run client App. Are they separated? Another think that came to my mind is using
Platform.runLater(()->{
});
if your client GUI is in JavaFX. Use it if you are creating GUI, changing values in fields and anything you do on your GUI. Maybe your server is waiting for user response and after that GUI is built? Which causes that you can't press DELETE button.
I'm not currently able to comment, so I can't ask for clarification, but I think I'm correctly interpreting what's wrong. "The program hangs when it enters a loop that waits for input from two controllers". Assuming I got that part right, the most likely culprit would be that buffered reader is hanging indefinitely because its not receiving input. When I first ran into this issue, I threw it inside its own "receiver" class and used a Queue to bus over anything it received to a loop in my main class. my code looked something like this:
import java.io.BufferedReader;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
public class Listener implements Runnable
{
private BufferedReader br;
private BlockingQueue<String> q;
private boolean shouldClose = false;
public Listener(BufferedReader br, BlockingQueue<String> q)
{
this.q = q;
this.br = br;
}
public void run()
{
loop();
System.out.println("listener has stopped");
}
public void loop()
{
String line = "";
try
{
while((line = br.readLine()) != null && !shouldClose)
{
q.put(line);
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
}
public void shutdown()
{
shouldClose = true;
}
}
apologies if I've misunderstood in any way, or missed something in your code.
I was trying to get the logcat content into a JTextPane. I used following code hoping it will return the content as String but it freeze and also, doesn't produce an error.
Process exec = null;
try {
exec = Runtime.getRuntime().exec("adb logcat -d");
InputStream errorStream = exec.getErrorStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(errorStream));
String errorLine;
while ((errorLine = ebr.readLine()) != null) {
System.out.println("[ERROR] :- " + errorLine);
}
if (exec.waitFor() == 0) {
InputStream infoStream = exec.getInputStream();
InputStreamReader isr = new InputStreamReader(infoStream);
BufferedReader ibr = new BufferedReader(isr);
String infoLine;
while ((infoLine = ibr.readLine()) != null) {
System.out.println("[INFO] :- " + infoLine);
}
}
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
} finally {
if (exec != null) {
exec.destroy();
}
}
I referred to some tutorials but, they were not filling my problem. Is this wrong? Are there any other methods to get the logcat content as a String programmatically? Sorry if this is a dumb question.
The issue you're seeing is that you're trying to process command streams and wait for the executing process, all in the same thread. It's blocking because the process reading the streams is waiting on the process and you're losing the stream input.
What you'll want to do is implement the function that reads/processes the command output (input stream) in another thread and kick off that thread when you start the process.
Second, you'll probably want to use ProcessBuilder rather than Runtime.exec.
Something like this can be adapted to do what you want:
public class Test {
public static void main(String[] args) throws Exception {
String startDir = System.getProperty("user.dir"); // start in current dir (change if needed)
ProcessBuilder pb = new ProcessBuilder("adb","logcat","-d");
pb.directory(new File(startDir)); // start directory
pb.redirectErrorStream(true); // redirect the error stream to stdout
Process p = pb.start(); // start the process
// start a new thread to handle the stream input
new Thread(new ProcessTestRunnable(p)).start();
p.waitFor(); // wait if needed
}
// mimics stream gobbler, but allows user to process the result
static class ProcessTestRunnable implements Runnable {
Process p;
BufferedReader br;
ProcessTestRunnable(Process p) {
this.p = p;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(p.getInputStream());
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null)
{
// do something with the output here...
}
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
I'm trying to use BufferedReader.read(char[]) method instead of the easier, but less versatile BufferedReader.readLine() method for receiving an answer from a Server. BufferedReader is used in parallel with BufferedOutputStream and, in the code below, the read(char[]) method blocks everything, the last console output is "new buffer, waiting to read."
Client:
public class MessageSender extends Thread {
private String message;
MessageSender(String message) {
this.message = message;
}
public void run() {
try {
Socket sk = new Socket("192.168.1.4", 3000);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write(message.getBytes());
bo.flush();
char[] c = new char[100];
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
StringBuffer sb = new StringBuffer();
System.out.println("new buffer, waiting to read.");
int ix = 0;
while (ix != -1) {
ix = br.read(c);
sb.append(new String(c));
}
String message = sb.toString();
System.out.println("reply: " + message);
sk.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Server:
public class MessageReceiver extends Thread {
public void run() {
try {
ServerSocket ss = new ServerSocket(3000);
System.out.println("server socket open");
while (true) {
Socket sk = ss.accept();
System.out.println("new connection");
BufferedReader br = new BufferedReader(new InputStreamReader(sk.getInputStream()));
String line = br.readLine();
System.out.println("received line: " + line);
BufferedOutputStream bo = new BufferedOutputStream(sk.getOutputStream());
bo.write("ack".getBytes()); bo.flush(); //bo.close();
sk.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Main:
public class Main {
public static void main(String[] args) {
MessageReceiver mr = new MessageReceiver();
mr.start();
while (true) {
String msg = new Scanner(System.in).nextLine();
MessageSender ms = new MessageSender(msg+"");
ms.start();
}
}
}
Everything works fine as long as the BufferedReader.read is not called. But as the code is right now, the output doesn't seem to get sent to the server.
UPDATE
As answered by #JB Nizet, the problem lies in the server script that uses readLine() and waits for either EOL character or the connection end. Therefore, adding "\n" to the message sent from the client side solved the deadlock:
bo.write((message+"\n").getBytes());
When the server accepts a connection from the client, the first thing it does is:
String line = br.readLine();
So, it blocks until the client sends a complete line of text. The server only knows the line is complete if it reads an EOL character, or if the stream is closed by the client.
When the client starts, the first thing it does is
bo.write(message.getBytes());
And message is a line of text, without any EOL. Then the client does
ix = br.read(c);
so it waits for a response from the server, which is itself waiting for an EOL from the client.
You have implemented a networked deadlock.
Using an self-edited StreamGobbler to run a php script,
I am trying to input commands into the script while it is running...
StreamGobbler.java
private class StreamGobbler extends Thread {
InputStream is;
OutputStream os;
String line;
PMRunnerPro main;
public StreamGobbler(InputStream is, OutputStream os, PMRunnerPro main) {
this.is = is;
this.os = os;
this.main = main;
}
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader (new InputStreamReader(is));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
if (main.sSendNeeded) {
System.out.println("Sent");
writer.write(main.sCommand + "\n");
main.sSendNeeded = false;
main.sCommand = "";
}
main.outputBox.setText(main.outputBox.getText() + (line + "\n"));
line = reader.readLine();
}
writer.flush();
} catch(IOException ex) {
main.sRunning = false;
}
System.out.println("Over");
main.sRunning = false;
}
}
The command is sent to the script only when there is an output from the script.
I want the Thread to continuously check if there is any command to send to the script and then do so if there is any.
If I understood your intentions correctly...
Since you using blocking I/O, you need two threads for what you want:
1st thread will read script output, as you do now. Once output available, it will be shown in textarea;
2nd thread will read input from queue and forward it to script.
Here's code draft (notice that you may want to add synchronization between input and output workers, so input worker won't be able to send new command to script until previous command produces output from script, but that's up to you):
class InputWorker implements Runnable {
#Override
public void run() {
try {
BufferedReader reader = new BufferedReader (new InputStreamReader(is));
String line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
// show script output
}
} catch(IOException ex) {
//
}
}
}
class OutputWorker implements Runnable {
final BlockingQueue<String> commandQueue = new ArrayBlockingQueue<String>();
public void sendCommand(String command) {
commandQueue.add(command);
}
#Override
public void run() {
try {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
while (true) {
String command = commandQueue.take();
if ("EXIT".equals(command)) { return; }
writer.write(command);
writer.flush();
}
} catch(IOException ex) {
//
} catch (InterruptedException e) {
//
}
}
}
Here is the situation:
I have a java application which executes another java application example.exe (example.exe has some System.out.println("...");)
I want to get the output Stream from example.exe so i tried with something like that:
(looks pretty standard)
final Process process = Runtime.getRuntime().exec("example.exe");
new Thread() {
public void run() {
try {
BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
try {
while((line = inputReader.readLine()) != null) {
inputText = inputText + line;
}
System.out.println(inputText);
} finally {
inputReader.close();
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
I would like to get the output messages of example.exe but it doesn't work and i don"t understand why, i get one message but not the one from example.exe, probably from java or something else.