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...
Related
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.
I'm trying to create a simple Chat program, I found all kinds of example but yet I do try to accomplish it from scratch.
I have Server class (extends thread) and a GUI class, when either Connect or Disconnect buttons are clicked the GUI is halted (stuck)
Server code:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
* #author Shahar Galukman
*/
public class ChatServer extends Thread{
ServerSocket ss;
boolean serverStopped = false;
private int port = 18524;
public ChatServer(){
serverStart();
}
private void serverStart(){
//Create new server socket
try {
ss = new ServerSocket(port);
} catch (Exception e) {
System.out.println("An error eccurd connection server: " + e.getMessage());
}
//wait for clients to connect
while(!serverStopped){
try {
Socket clientSocket = ss.accept();
/*
* Code will halt here until a client socket will be accepted.
* Below a new client thread will be created
* enabling multi client handling by the server
*/
//create new ChatClientThread here
} catch (IOException ex) {
System.out.println("Error accpeting client socket");
}
}
}
//Stop the server
public void stopServer(){
serverStopped = true;
ss = null;
}
}
And i have a simple SWING GUI having connect and disconnect buttons, I'm using a inside class called Handler to add action listener to the bottons.
Handler class (located in the end of the GUI class:
//inner class
class Handler implements ActionListener
{
//This is triggered whenever the user clicks the login button
#Override
public void actionPerformed(ActionEvent ae)
{
ChatServer server = new ChatServer();
//checks if the button clicked
if(ae.getSource()== connectButton)
{
try{
server.start();
serverStatusField.setText("Connected");
}catch(Exception e){
e.printStackTrace();
}
}else if(ae.getSource()== disconnectButton){
server.stopServer();
serverStatusField.setText("Disconnected");
}
}
}
Also in the GUI class I'm adding the action listener to the bottuns as follows:
public GUI() {
initComponents();
//create new handler instance
handle = new Handler();
connectButton.addActionListener(handle);
disconnectButton.addActionListener(handle);
}
When I click on the connect bottun a new Server thread is starting, as far as I understand. so why is the GUI get stuck? Should I use multi threading here?
In your serverStart method, you have a sort of infinite loop which waits for the server to stop. When this button is called, the caller thread while certainly loop forever and block other calls.
In Swing, GUI is handled by the main thread. So if you call serverStart from the main thread, the gui will block until the loop is broken which will never happen.
Therefore, yes you should use mutithreading and call serverStart on another independant thread.
Normally, you should go for the following solution:
Thread for GUI calls (dynamic gui handling ...)
Thread(s) for heavy backend work (Socket connections, Data loading ..)
EDIT:
Here's a nice oracle tutorial about thread:
http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
2nd EDIT:
There is also something wrong in your code. Why is the method serverStart called in the constructor of ChatServer and not on the run method overriden from Thread? In that case, the infinite loop is called on the main thread when the ChatServer thread is constructed. I think you should call the serverStartin the run method of Thread:
ex:
public class ChatServer extends Thread{
....
public ChatServer(){
}
#Override
public void run {
serverStart();
}
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.
I'm trying to create a chat program in java but I had a problem when I run the server form, that the components I used to draw won't appear.
this is the code I used in the run of the form :
public void run() {
Server s = new Server();
s.setVisible(true);
// Etablir la connexion
try
{
ServerSocket ecoute;
ecoute = new ServerSocket(1111);
Socket service = null;
System.out.println("Serveur en attente d'un client !");
while(true)
{
service = ecoute.accept();
System.out.println("Client connécté !");
DataInputStream is = new DataInputStream(service.getInputStream());
s.jTextArea1.setText("Client dit : " + is.readUTF().toUpperCase());
service.close();
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
You said nothing happens when this code is ran. The presence of a public void run() method tells me that this is a thread, or at least a Runnable.
Because of the while(true), if this thread is not started in the proper manner, it will not run independently; that is it will hold up the entire program.
Instead of calling thread.run();, call thread.start();. This will call the run method for you, after starting a new thread that will run in parallel to the main thread.
If this code is not in a thread, and you just used public void run() by chance, then it will still provide the same problem for you.
For more information, refer to the Documentation on Threads
Im working on a socket program in Java.
Im running a GUI with a socket server in the background.
The socket server is running a thread that checks for socket messages every 10ms.
Both of them runs fine together but as soon as I try to open my File dialog in the gui, the gui crashes, but the server keeps on running.
Im thinking that I run the server (or the server thread) in a wrong way.
The file dialog works fine if I skip the socket.
What could be the problem, could it be that Im running the thread in a wrong way?
(this in one class)
public ServerController(){
ServSocket st = new ServSocket();
Thread thread1=new Thread(st);
thread1.start();
}
(this is my thread)
public void run(){
while (true) {
try {
Thread.sleep(10);
}
catch (InterruptedException e) {}
switch (Status) {
case CONNECTED:
try {
socket = new Socket(hostIP, port);
System.out.println("Connected on: " + hostIP + port);
out = new PrintWriter(socket.getOutputStream(), true);
changeStatus(STARTSENDING, true);
}
catch (IOException e) {
System.out.println("disconnected");
}
break;
(and this is my main)
static ServerController scon;
static Controller cn;
public static void main(String[] args) {
scon = new ServerController();
cn = new Controller();
cn.gui();
}
Just guessing here, but I think it's relating to the EDT.
Are you trying to launch the dialog from outside the EDT? http://en.wikipedia.org/wiki/Event_dispatching_thread
If you think you might be, try using SwingUtilities static methods (specifically isEventDispatchThread and invokeLater) to hone in and rectify the issue:
http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html#isEventDispatchThread()
http://java.sun.com/javase/6/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)
hth
The problem is now solved.
Seems that the problem was that i had a scanner that was waiting for input(string = sc.next();) every 10ms in the thread, and after a few input my GUI showed.
I removed the Scanner and i now have a working application.