Good day,
I have an infinite loop for a ServerSocket, working fine... The problem is when I try to start the ServerSocket with a button. My user interface "Freeze" don't move, anything, but the server is up and fine, here I have a ScreenShot:
http://i.gyazo.com/15d331166dd3f651fc7bda4e3670be4d.png
When I press the button "Iniciar" means Start server, the User Interface Freezes (ServerSocket infinite loop). I can't change my code because its working fine.
public static void iniciarServer() {
try {
appendString("\nServidor iniciado.");
System.out.println("asdasd");
} catch (BadLocationException e1) {
e1.printStackTrace();
}
try {
ss = new ServerSocket(1234, 3);
while (true) {
System.out.println("Esperando conexiones...");
appendString("\nEsperando conexiones...");
Socket s = ss.accept();
System.out.println("Conexión entrante: " + s.getRemoteSocketAddress());
appendString("\nConexión entrante: " + s.getRemoteSocketAddress());
conexiones++;
//System.out.println("Debug: conexiones SERVER: " + conexiones);
MultiThread mt = new MultiThread(s, conexiones);
mt.start();
///////////////////////////////////////////////////////////////
}
} catch (IOException e) {
System.out.println("Error Server: " + e.getMessage());
} catch (BadLocationException e) {
e.printStackTrace();
}
stopServer();
}
appendString();
Is for add some text to the JTextPane, but doesnot work because the UI freezes.
Is there any way to do an user interface that don't freeze by the infinite loop?
Thanks!
Swing is a single threaded framework, meaning any blocking or long running operation executed within the context of the Event Dispatching Thread will prevent it from processing the Event Queue, making your application hang.
It's also not thread safe, so you should never try and modify the state of any UI component from out side of the EDT.
Take a look at Concurrency in Swing and Worker Threads and SwingWorker for more details
public class ServerSocketWorker extends SwingWorker<Void, String> {
private JTextArea ta;
public ServerSocketWorker(JTextArea ta) {
this.ta = ta;
}
#Override
protected void process(List<String> chunks) {
for (String text : chunks) {
ta.append(text);
}
}
#Override
protected Void doInBackground() throws Exception {
ss = new ServerSocket(1234, 3);
while (true) {
publish("\nEsperando conexiones...");
Socket s = ss.accept();
publish("\nConexión entrante: " + s.getRemoteSocketAddress());
conexiones++;
//System.out.println("Debug: conexiones SERVER: " + conexiones);
MultiThread mt = new MultiThread(s, conexiones);
mt.start();
///////////////////////////////////////////////////////////////
}
}
#Override
protected void done() {
stopServer(); //??
}
}
To start it, you could use something like...
public void iniciarServer() {
ServerSocketWorker worker = new ServerSocketWorker(textAreaToAppendTo);
worker.execute();
}
As an example
The method ServerSocket.accept() is a blocking method. This means that Socket s = ss.accept(); stops the current thread until a connection to the server socket is opened.
Event dispatching in Swing is single threaded, the while loop and the blocking operation mentioned above, will keep the thread 'busy' and block all other interactions with the UI.
You should run your entire while loop in a separate thread. When you want to stop the server, you should also ensure that the while loop is exited and the thread completes execution.
Related
tl, dr;
I have a GUI thread that creates an object of another class (the seconds class has implemented Runnable, but here we don't execute the run() method, instead, we call a normal method) and calls a method. In that method, the first thread (current thread) is called again (to show sth on the LCD), then sends some data to the Internet, and waits 3 seconds for the server response. The problem is that the information is printed after 3 seconds. I know about the stack and program counter, but I wonder if there is another option that I can do my job.
I have the main method, which runs 3 threads (for short, I just write the requisite code. Tell me to add more, if needed):
public static void main(String[] args) throws UnknownHostException, InterruptedException {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI.getInstance().setVisible(true); //GUI is singleton, using swing and JFrame
} catch (Exception e) {
e.printStackTrace();
}
}
});
MQTTConnection.getInstance().tryToConnect(); //It's the connection class, which has a thread (the thread is handled by a library that keeps the connection alive. I have no threads there) and is a singleton too.
Thread t1 = new Thread(new SendDataThread()); //A thread which sends some data every 20 seconds.
t1.start();
}
And in SendDataThread, I have a function that creates some random data and sends them (using the MQTTConnection class).
This is the SendDataThread:
public class SendDataThread implements Runnable {
public void sendLog() {
boolean serverOnline = false;
StringBuilder data = new StringBuilder();
data.append(createData());
GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
if(MQTTConnection.getInstance().publishLog(MQTTConnection.getInstance().MQTT_PUBLISH_ESP_SEND_LOG, data.toString())) //This line has a 3 second timeout. If the server doesn't respond, it will return false. I've added the 3 seconds timeout too. Please continue reading.
serverOnline = true;
if(serverOnline)
GUI.getInstance().printOK("Server Submitted"); //Prints in GREEN
else
GUI.getInstance().printProblem("Check your connection!"); //Prints in RED
GUI.getInstance().printNeutral("-------------------------------------------------");
}
#Override
public void run() {
while(true) {
sendLog();
try {
Thread.sleep(20000); //sleeps 20 about seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//.....
}
And this is the 3 seconds timeout method, in MQTTConnection:
boolean publishLog(String topic, String data){
mqtt_responds = false;
publish(topic, data);
System.out.println("MQTT is connected");
long lastTime = System.currentTimeMillis();
while(System.currentTimeMillis() - lastTime < callback_timeout) {
if(mqtt_responds){
mqtt_responds = false;
System.out.println("Server submitted");
return true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Timeout");
return false;
}
Till now, everything work right. The problem starts where I have a button in the GUI class, which the user can manually send random logs:
JButton sendLogBtn = new JButton("Send Log");
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SendDataThread sdt = new SendDataThread();
sdt.sendLog();
}
});
sendLogBtn.setBounds(10, 331, 89, 23);
panel.add(sendLogBtn);
This button creates an object of SendDataThread and calls the sendLog() method. The issue happens here: after sendLog() is called, sendLog(), calls this GUI thread again:
--> GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
But the log is printed after 3 seconds (After the sendLog() method has finished working, the timeout!)
How can I fix this?
In the button's actionPerformed you are calling sendLog. sendLog does exactly what you said, ie reports some logs and waits about 3 seconds (assuming callback_timeout is about equal to 3000).
To fix this, you need to make sure that the 3sec blocking is not on the EDT and also to make sure that the logs are instead posted on the EDT.
As a quick workaround you can do:
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> new SendDataThread().sendLog()).start();
}
});
and then, as always, post your logs in the EDT like for example:
SwingUtilities.invokeLater(() -> GUI.getInstance().printNeutral(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printProblem(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printOk(...));
As for the question in your comment, I don't really understand what you are asking, but I should say that (as far as I know) the EDT is a Thread where all the Swing code is (and should be) posted on for execution. This way the Swing code does not have to be synchronized, because all GUI related stuff is executed sequentially (on the EDT). AWT for example was not intended to be single threaded as far as I know. Swing is however single threaded.
In following code i am trying to start and stop the server on button using java applet.Start works good using thread but i want to stop the server on button. I have used volatile variable.Still i am not getting the server stop..
here is code:
public class TCPServer extends Thread {
public static final int SERVERPORT = 8002;
private boolean running = false;
public volatile boolean stop = false;
public Socket client = null;
public static void main(String[] args) {
ServerBoard frame = new ServerBoard();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public void run() {
super.run();
running = true;
try {
System.out.println("Server Has Started........ \n Waiting for client........");
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
try {
while (!stop && running) {
client = serverSocket.accept();
System.out.println("Connection Accepted......");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
String usercmnd = in.readLine();
if (usercmnd != null) {
Runtime runtime = Runtime.getRuntime();
Process p = runtime.exec(usercmnd);
}
}
if (stop) {
serverSocket.close();
client.close();
System.out.println("Server Has Stopped");
System.exit(0);
}
} catch (Exception e) {
System.out.println("Error");
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("Error");
e.printStackTrace();
}
}
public void requestStop() {
stop = true;
}
}
But whenever i click the stop button which will stop the server.Its not showing any output on console as i expected by the code.Its also not showing any error
here is code of stop button
stopServer = new JButton("Stop");
stopServer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stopServer.setEnabled(false);
startServer.setEnabled(true);
mServer = new TCPServer();
mServer.requestStop();
}
});
It doesn't stop because you create a new instance before stopping it and you don't even start it first while you are supposed to call requestStop() on your current instance of TCPServer.
// Here you create a new instance instead of using the existing one
mServer = new TCPServer();
mServer.requestStop();
in your ActionListener implementation for the stop button, you are accessing a different instance of TCPServer (as you are creating a new one). So you set the value "Stop" to a second object. It has no impact on the first instance that was created with the start button.
Try to instanciate the TCServer outside of your implementation of the action listener for both buttons and use that single instance for both.
Due to https://docs.oracle.com/javase/7/docs/api/java/net/ServerSocket.html#accept()
ServerSocket::accept is a blocking method, so stop variable can only be checked between successful connections.
You can either set a ServerSocket timeout using ServerSocket::setSoTimeout (and catch SocketTimeoutException), or interrupt Server thread and catch InterruptedException.
Both exceptions will be throwed from ServerSocket::accept.
Note, that thread interruption is highly preferred over timeouts and repeatly exception catching.
Try this:
public void requestStop() {
stop = true;
interrupt();
}
However, in this case, we can not guarantee, that already processing logic will successfully shutdown.
Also, you try invoke requestStop for new instance of TCPServer, instead already existing.
your code client = serverSocket.accept(); is blocking. So once you clicked "stopServer" button, you requested the stop, but it will be acted upon only once a client sends a next request to the server. What you need to do is to run your logic in your method run() in a separate thread and catch there InterruptedException and ClosedByInterruptException and clean up and return there. On your stopButton click you will invoke interrupt() method on your Thread. Read about it in here
I've been trying to figure it out for some time,
I'm trying to write a chat - server app, just for learning.
I have an obstacle that I cannot understand,
The while loop inside of the GUI class freeze, but just when it trying to read:
public void run(){
Platform.runLater(() -> {
do {
try {
msg = getFromServer.readUTF(); // <--- freeze GUI
chatWindow.appendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
} while (true);
});
}
You can see that it's running in a thread, but i did try to run it in other ways...
Only the DataInputStream make it stuck,
msg = getFromServer.readUTF();
And this it the methud that it's coming from:
public void connectToServer(){
try {
serverConectionState = new Socket("127.0.0.1", 6789);
getFromServer = new DataInputStream(serverConectionState.getInputStream());
sendToServer = new DataOutputStream(serverConectionState.getOutputStream());
onlineOffline.setText("Online");
onlineOffline.setTextFill(javafx.scene.paint.Color.web("#0076a3"));
} catch (IOException ex){
chatWindow.appendText("server connection fail\n");
}
}
This class, is the Controller.class - if it's make any diffrent.
My first question in stackoverflow, after a lot of help from the community.
Thanks in advance
I'm assuming the run method you showed is part of a Runnable that is executed in a background thread.
You are running the entire loop on the FX Application Thread (by using Platform.runLater()). So you block that thread and prevent it from repainting. You should run only the UI updates on the FX Application Thread:
public void run(){
do {
try {
String msg = getFromServer.readUTF(); // <--- freeze GUI
Platform.runLater(() -> chatWindow.appendText(msg));
} catch (IOException e) {
e.printStackTrace();
}
} while (true);
}
instead of using platform.runlater you should use java task, so that you can run the code in different thread, without freezing the UI thread
I'm writing a Java GUI multiplayer game.
I have a GUI where user can enter port number and click on "start server" which will initiate game server and bring up another GUI frame. But my program freezes when the button is clicked.
Is it okay to start server using this way or how can I code so that server will be started and waiting for players to be connected and at the same time display another GUI frame (written in a separate class)? Thanks in advance.
// part of GUI code
start = new JButton ("Start Game Server");
start.addActionListener (new ActionListener() {
public void actionPerformed (ActionEvent event) {
DEFAULT_PORT = Integer.parseInt(port.getText());
fgServer.run();
fgServerFrame = new FishingGameServerFrame();
//frame.dispose();
}
});
--
// server code
public class FishingGameServer {
private static int DEFAULT_PORT = 0;
public void run()
{
int port = DEFAULT_PORT;
port = Integer.parseInt(FishingGameConnectServerFrame.portNumber());
System.out.println("port #: " + port);
//setup server socket
ServerSocket reception_socket = null;
try {
reception_socket = new ServerSocket (port);
System.out.println("Started server on port " + port);
}
catch (IOException e) {
//to get text in GUI frame
System.out.println("Cannot create server");
System.exit(0);
}
for (;;) {
Socket client_socket = null;
try {
client_socket = reception_socket.accept();
System.out.println("Accepting requests from:" + client_socket.getInetAddress());
}
catch (IOException i) {
System.out.println ("Problem accepting client socket");
}
new FishingGameThreadedServer(client_socket);
}
}
public static void main (String[] args) {
new FishingGameServer().run();
}
You call fgServer.run();, which eventually calls client_socket = reception_socket.accept(); within an infinite loop.
This is preventing the Event Dispatching Thread from been able to run, by blocking (once within the neverending for-loop and once when using accept) it can not process the Event Queue, which is responsible for, amongst other things, processing paint requests.
Swing is a single threaded environment, it is also not thread safe. This means:
You should never perform any long running or blocking operations within the context of the EDT and
All updates and interactions with the UI must be made from within the context of the EDT
Take a look at Concurrency in Swing for more details
You could use a Thread instead or a SwingWorker which provides functionality to more easily publish updates back to the EDT...
My Server is build around support to update the listening socket, by doing so I use the following method. my problem occurs after this method is called for the second time, this is first called at start up from the main method then later it is called by clicking a button in a JFrame. what happens is that the JFrame freezes when this method is called via button, as you can see by the code I tried to make this method run a server in a new thread but it hasn't changed my outcome. Does anyone know how to fix this? or at least what is causing it? also any code after the method is called in the main doesn't get execute, so I believe it is a thread problem. (MiniServer extends Thread and is used to handle each connected client individually)
public static void startListening(final int port)
{
listeningThread = new Thread()
{
public void run()
{
try {
serverSocket = new ServerSocket(port);
while(!stop)
{
boolean loop = true;
while (loop)
{
serverSocket.setSoTimeout(1000);
try{
clientSocket = serverSocket.accept();
loop = false;
} catch (SocketTimeoutException e){
}
}
if(!clientSocket.equals(null))
{
MiniServer mini = new MiniServer(clientSocket);
mini.start();
clientSocket = null;
}
}
} catch (IOException e) {
}
}
};
listeningThread.run();
}
You need to be calling listeningThread.start(), which will create a new thread. Right now, you're just calling the thread's run() method on the current thread. The first time you do that it works, since you're on the main thread. The second time, though, you're on the UI thread, reacting to the button press. This causes your UI thread to block.