Reputation: 351
My application keeps loading (circle cursor). Here is my code
public class ControllerW {
@FXML
private Label statusLbl, timeLbl, textLbl;
@FXML
private Button exitBtn, linkBtn;
private ServerSocket serverSckt;
private Socket clientSckt;
DataInputStream dis;
String text;
@FXML
private void exit() {
System.exit(0);
}
@FXML
private void linkAndroid() {
try {
serverSckt = new ServerSocket(5678);
statusLbl.setText("Server started");
clientSckt = serverSckt.accept();
statusLbl.setText("client connected successfully");
dis = new DataInputStream(clientSckt.getInputStream());
text = dis.toString();
textLbl.setText(text);
} catch (Exception e) {
statusLbl.setText("No connection on port 5678");
e.printStackTrace();
}
}
}
I am new to socket programming, could someone please help me if there is anything wrong with my code
Upvotes: 0
Views: 315
Reputation:
First you run the socket with the GUI/JFX thread. so accept()
will block it (UI won't be responsible, dat circle you know).
You need to run the IO/socket with another thread. but beware, you need to change the UI stuffs with UI thread. (for example textLbl.setText(text);
may fail if is called from another thread directly)
Also this line text = dis.toString();
is nonsense, you supposed to get a string sent from client? So use(recommended) readLine()
method from BufferedReader
instead of DataInputStream
. (readUTF
may work from DataInputStream
too).
Upvotes: 0
Reputation: 1772
Your application is stopping to respond because it's not threaded. Without multithreading your application will 'stop' the moment you click your "link" button because the call to ServerSocket#accept
.
The reason for that is the blocking nature of the accept
method. Until another socket connects the ServerSocket
is waiting and keeps his current thread 'suspended'. Think of it as an inner while loop similiar to this:
while(!isConnected())
{
// check if there is a new request
}
Imagine no client would ever connect. How would this loop ever stop? Never.
A possible workaround is to either thread the entire UI part or 'data model' part.
My prefered way is to create a custom class which only handles the ServerSocket#accept
method and delegates incoming connections to another thread which takes care of the rest. I do that to keep my server accessible at any time which might not be the best approach for your problem.
This is how my helper class commonly looks like:
ClientAccepter.java:
public class ClientAccepter
implements Runnable
{
// the ServerSocket
private final ServerSocket server;
// ExecutorServices ease the pain of threading your application quite a lot
private final ExecutorService es = Executors.newCachedThreadPool();
private boolean isAlive = true;
public ClientAccepter( ServerSocket server )
{
this.server = server;
}
@Override
public void run()
{
//This is where you specify your desired behaviour.
//Example:
while ( isAlive )
{
try
{
es.execute( new ClientHandler( server.accept() ) );
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
}
The call to such a class could look like this:
Server.java:
public class Server
{
//ExecutorServices are the best and easy to use.
private static ExecutorService serverThreader = Executors.newSingleThreadExecutor();
public static void main( String[] args )
{
try
{
serverThreader.execute( new ClientAccepter( new ServerSocket( 8080 ) ) );
}
catch ( IOException e )
{
e.printStackTrace();
//further exception handling.
}
}
}
To be fair this might not be the best approach but it's my preferred way of handling blocking operations. You should consider working through the orcale concurrency tutorial and definitly take a look at ExecutorServices
because they are an incredible framework to handle threadpools with ease.
Also specificly for JavaFX there is a concurrency tutorial.
Upvotes: 2