I'm implementing a very basic API to have a better control over ServerSocket and Sockets, but I'm in a very weird problem that I cannot fix due to my lack of threads knowledge. Let me explain it.
In my class SocketStreamReceiver I use a secondary thread to listen for new sockets with ServerSocket#accept(). There are 2 methods: start() and stop() that the client can use to start (creating a thread and begin listening with accept()) and stop (closing the ServerSocket and destroying the thread) my SocketStreamReceiver.
How will you implement stop() method? Keep in mind that stop() can be called inside doSomething(), in the same secondary thread started by start(). You can change anything you want: you can create the ServerSocket inside the thread if you want, just before while(running).
public class SocketStreamReceiver{
...
private Thread thread;
private ServerSocket server;
private boolean running;
...
public void start () throws IOException{
if (thread != null) return;
server = new ServerSocket (port);
thread = new Thread (new Runnable (){
#Override
public void run (){
try{
while (running){
Socket socket = server.accept ();
doSomething (socket);
}
}catch (SocketException e){
...
}catch (IOException e){
...
}
}
}, "SocketStreamReceiver");
thread.start ();
}
public void stop () throws IOException{
if (thread == null) return;
//code...
thread = null;
}
}
Thanks.
EDIT - Solution:
public class SocketStreamReceiver{
private Thread thread;
private ServerSocket server;
private volatile boolean running;
...
public synchronized void start () throws IOException{
if (thread != null) throw new IllegalStateException ("The receiver is already started.");
server = new ServerSocket (port);
thread = new Thread (new Runnable (){
#Override
public void run (){
try{
running = true;
while (running){
doSomething (server.accept ());
...
}
}catch (SocketException e){
...
}catch (IOException e){
...
}
}
}, "SocketStreamReceiver");
thread.start ();
}
public synchronized void stop (){
if (thread == null) return;
running = false;
try{
if (server != null){
server.close ();
}
}catch (IOException e){}
thread = null;
}
}
I would just do
public void stop() {
running = false;
try{
if (server != null) server.close ();
} catch (IOException ignored){
}
}
It doesn't appear you even need the running flag. However I would use it in your server accept code to determine if an Exception is expected or not. i.e. when running == false ignore all exceptions.
I would make running volatile.
I would make start()/stop() synchronized if you can run these from different threads.
Related
I have a basic server thread in which I accept sockets with the accept () function. For a certain period of time, I would need to avoid connecting new sockets. I want to do this from another thread by telling the server thread to not make new connections.
public class ServerThread extends Thread {
private boolean running = false;
private final ConnectionManager connectionManager;
private final AtomicBoolean acceptNewConnections;
ServerThread(ConnectionManager connectionManager, int port) {
super("ServerThread");
this.connectionManager = connectionManager;
this.port = port;
this.acceptNewConnections = new AtomicBoolean(false);
}
// This is called from other threads
public void setAcceptNewConnections(boolean value) {
acceptNewConnections.set(value);
}
#Override
public void shutdown() {
acceptNewConnections.set(false);
running = false;
try {
join();
} catch (InterruptedException ignored) {}
}
#Override
public void run() {
running = true;
connectionManager.serverThreadStart();
try (ServerSocket serverSocket = new ServerSocket(port)) {
acceptNewConnections.set(true);
while (running) {
try {
if (acceptNewConnections.get()) {
final Socket socket = serverSocket.accept();
if (acceptNewConnections.get()) connectionManager.addClient(socket);
else socket.close();
} else {
try {Thread.sleep(10);} catch(InterruptedException e){}
}
} catch (SocketTimeoutException ignored) {
//
}
}
} catch (IOException e) {
//
}
connectionManager.serverThreadStop();
}
}
My questions are:
Is there a way to interrupt waiting for a new socket while waiting?
Is there a way to wait for a new socket, but would accept it as needed after waiting for it, not wait and accept it in one command?
How can I pause the server thread while blocking new connections without using Thread.sleep() and useless overusage of cpu?
Thank you so much for help.
I'm having problems to terminate a thread that waits on accept() call.
accept(): Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
I have GestorBuzon which implements the Runnable interface:
public class GestorBuzon implements Runnable{
private static volatile boolean running = true;
public void run() {
try {
while (running) {
-- pre code
accept();
-- post code
}
} catch(IOException e) {
terminate();
}
}
public static void terminate() {
running = false;
}
}
And I have MessageSystem class which starts and stops the thread:
public class MessageSystem {
private GestorBuzon gestorBuzon;
private Thread thread;
public MessageSystem() {
// Starts the Thread
contextInitialized();
}
private void contextInitialized() {
gestorBuzon = new GestorBuzon();
thread = new Thread(gestorBuzon);
thread.start();
}
private void contextDestroyed() {
if (thread != null) {
gestorBuzon.terminate();
try {
thread.join();
} catch (InterruptedException e) {
gestorBuzon.terminate();
}
}
}
}
I call the accept() function in Runnable class multiple times, but when I use contextDestroyed() function, the Thread is still waiting on accept() and the Thread doesn't terminate. What am I doing wrong?
It have to do this:
Just set a socket timeout on the ServerSocket via setSoTimeout(), and catch SocketTimeoutExceptionwhen it fires. You can then inspect your running flag in the catch block etc. and decide whether to continue or stop accepting.
i'm trying to run a javafx application from a thread outside the scope of the application class. Th problem i'm using a while loop to generate the application and it throws an illegalstatexception whenever it is called twice, so i need a way to distinguish if the application is already running to continue with my other tasks, any ideas?
Based on #nejinx 's answer, you have to do this when calling Application.launch():
try {
Application.launch(args);
} catch (IllegalStateException e) {}
That way, if the error happens, your program will just keep running and not try to start the application again.
public class MyServer implements Runnable{
public static final int PORT = 99 ;
private static ServerSocket serverSocket;
private Window window;
public MyServer(Stage window) throws AlreadyBoundException {
if(serverSocket!=null && !serverSocket.isClosed())
throw new AlreadyBoundException("The server is already running.");
this.window = window;
try( Socket clientSocket = new Socket("localhost", PORT);) {
Platform.exit();
} catch (IOException e) {
final Thread thread = new Thread(this);
thread.setDaemon(true);
int priority = thread.getPriority();
if(priority>Thread.MIN_PRIORITY)
thread.setPriority(--priority);
thread.start();
}
}
public void run() {
try {
serverSocket = new ServerSocket(PORT, 1);
while (true) {
Socket clientSocket = serverSocket.accept();
clientSocket.close();
Platform.runLater(()->window.requestFocus());
}
}catch (IOException e) {
System.out.println("Error in MyServer: " + e);
}
}
}
And in the JavaFX APP:
#Override
public void start(Stage stage) throws Exception {
// Start server
new MyServer(stage);
// ...
}
The only way you can do this is to catch the IllegalStateException
If you dig down into the JavaFX source code you see this:
if (launchCalled.getAndSet(true)) {
throw new IllegalStateException("Application launch must not be called more than once");
}
So, this is what I have. This is a server program that connects to multiple clients by using threads. As of now, that main loop is pretty much infinite.
Say a client sent a shutdown command to a ServerThread. Would that ServerThread be able to access the main class, break out of the loop, and reach the end of the program?
I tried turning putting isRunning = false in the ServerThread, but that doesn't seem to work.
public class Server
{
public static boolean isRunning = true;
public static void main(String[] args)
{
// init stuff
try {
serverSocket = new ServerSocket(27647);
} catch (IOException e) {
println("Could not listen on port 27647");
}
while(isRunning)
{
Socket clientSocket = null;
try{
clientSocket = serverSocket.accept();
} catch(IOException e) {
println("Could not connect to client");
}
ServerThread serv = new ServerThread(clientSocket);
serv.start();
}
try {
serverSocket.close();
} catch (IOException e1) { }
}
}
You need to make isRunning volatile and you have to close the serverSocket to unblock the accepting thread. I suggest you have a method like
public void close() throws IOException {
isRunning = false;
serverSocket.close();
}
If you call this from any thread, the thread will stop almost immediately.
I have an app that listens to incoming connections on a specified hostname and port. The listening is invoked with the method listen() (see below), which waits constantly for an incoming connection using ServerSocket.accept(), creating a new Thread to handle the input stream.
private ServerSocket serverSocket;
private Thread listenerThread;
public void listen() throws IOException {
this.listenerThread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Socket socket = TheServerClass.this.serverSocket.accept();
// Create new thread to handle the incoming connection
}
catch (IOException exc) { }
}
}
});
this.listenerThread.start();
}
Now I want to stop the running of listenerThread. But when I call this.listenerThread.interrupt(), this doesn't work.
I thought you can stop a thread by interrupting it, so why isn't that working?
(Notice: A possible solution is to close the ServerSocket using this.serverSocket.close(), but can it be accomplished with interrupt() or something?)
Call serverSocket.close(),
I guess since you are not doing IO yet - you can not interrupt it, and since the accept() doesn't throw InterruptedException you won't be able to interrupt it. The thread is interrupted, but that flag you have to check for yourself Thread.isInterrupted().
See How can I interrupt a ServerSocket accept() method?.
The answer is in the question. You need to close the socket. It's done using serverSocket.close(). Thread.interrupt() doesn't care about sockets.
Use this:
public class MyThread extends Thread {
private boolean stop;
private ServerSocket serverSocket;
public MyThread(ServerSocket ss) {
this.serverSocket = ss;
this.stop = false;
}
public void setStop() {
this.stop = true;
if (this.ss != null) {
this.ss.close();
}
}
public void run() {
while (!stop) {
try {
Socket socket = serverSocket.accept();
// Create new thread to handle the incoming connection
}
catch (IOException exc) { }
}
}
}
and from the listen() method just call setStop() method of the thread.