I am making a simple telnet implementation in Java from ground up.
I have already made a simple socket connection between client and server work. My problem is just that the whole server application freezes when it is waiting for a connection - even though i am running it in a seperate thread. Is there any (preferably) simple way to get around this?
Thread starter snippet:
worker slave = new worker();
Thread slaveThread = new Thread(slave);
slaveThread.run();
Thread snippet:
public class worker implements Runnable{
public void run()
{
try
{
ServerSocket srv = new ServerSocket(1337);
System.out.println("Thread is running!");
Socket clientSocket = srv.accept();
System.out.println("Connection made.");
}catch (IOException e){
System.out.println("Failed.");
}
Thanks in advance!
Java Newbie
Yes i start the thread with calling run()
Although Thread implements Runnable, you aren't supposed to call run(). You should call Thread.start(), which calls run() in the new thread. If you call run() directly, the current thread is the one that executes it, not the Thread you created.
Related
I have received some code through a school project and I'm failing to understand the purpose of the use of threading in this scenario. The project requires use of a multi threading server to pass. I have the following thread implementation which of a new instance is created every time a new client connects.
The problem is that they are not using the run-method, in my understanding the thread exists when it finishes running the run-method. But even after the thread should have finished running it manages to send further the messages from the propertyStateListener. Why does this work and does this really count as a multi-threaded server?
Starts an instance of the ClientHandler every time a new client connects:
#Override
public void run() {
while (true) {
MessageProducer mp;
try {
Socket socket = serverSocket.accept();
new ClientHandler(socket).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The actual ClientHandler:
private class ClientHandler extends Thread implements PropertyChangeListener {
private Socket socket;
private ObjectInputStream ois;
private ObjectOutputStream oos;
private Message messagerecieved;
public ClientHandler(Socket socket) throws IOException {
this.socket = socket;
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
messageManager.registerListener(this);
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
messagerecieved = (Message) evt.getNewValue();
try {
oos.writeObject(messagerecieved);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
}
The problem is that they are not using the run-method, in my understanding the thread [exits] when it finishes running the run-method. But even after the thread should have finished running it manages to send further the messages from the propertyStateListener.
You are correct that the code is confusing for sure. They are creating a thread with each instance of ClientHandler but there is no run() method so the thread immediately exits after start() is called. The code would actually still work if ClientHandler did not extend thread.
Why does this work
It is the messageManager thread which is calling back to the ClientHandler.propertyChange(...) method which writes the results back to the socket, not the ClientHandler thread.
does this really count as a multi-threaded server?
There certainly are 2 threads at work here because you have the socket-accept thread and the messageManager thread. Whether or not this is a "multi-threaded server" depends on the assignment I guess. Certainly if there was supposed to be a thread per client then this code does not do that.
Sample https://github.com/spring-projects/spring-integration-samples/tree/master/basic/tcp-client-server is great to build a TCP Server application. Its simple and runs on JVM. It does not need any Application Server.
Sample uses command line input to run the program. I want the server to accept data only from the Socket port and not through the command line. If I remove the command line input, main thread is finishing and the program no longer accepts input from the port. I have to keep the main thread running all the time.
I am thinking some thing like this:
boolean isGatewayStopped = false;
while (!isGatewayStopped) {
try {
Thread.sleep(5000);
isGatewayStopped = getGatewayStatus();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I have two questions:
is there a clean way of making the Main thread continue to run?
How to know that Gateway is stopped? If the user sends TCP data as "quit" then gateway can be stopped. is there any way to know that gateway is stopped?
Thanks
Another solution is like this:
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(Application.class, args);
System.out.println("Hit 'Enter' to terminate");
System.in.read();
ctx.close();
}
You start the ApplicationContext and wait for the stop from the console input.
EDIT
For the case when you would like to stop program via an event in the application, you can register ApplicationListener and wait on the barrier before existing from the main:
CountDownLatch exitLatch = new CountDownLatch(1);
ctx.addApplicationListener(ContextClosedEvent e -> exitLatch.countDown())
exitLatch.await();
Now you should just come up with some logic in your application to call ctx.stop() there.
You can call wait() on the gateway thread from the main thread to make the main thread wait until gateway thread finishes. You'll need to call the notify() from gateway thread (when it should stop) to indicate that it's finished and waiting threads should proceed to run (in this case main will run and exit). An example can be found here.
Or else (a different solution for a very simple app), you can try something like following to read data from a main method and stop the program when the data read is equal to a command to stop the program:
class Server
{
static Executor pool = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = new ServerSocket(9000);
while (true)
{
final Socket s = serverSocket.accept();
Runnable r = new Runnable()
{
#Override
public void run()
{
// read data from socket 's' here
// call System.exit() if command is to stop.
}
};
pool.execute(r);
}
}
I'm writing a client/server application in Java using sockets. In the server, I have a thread that accepts client connections, this thread runs indefinitely. At some point in my application, I want to stop accepting client connection, so I guess destroying that thread is the only way. Can anybody tell me how to destroy a thread?
Here's my code:
class ClientConnectionThread implements Runnable {
#Override
public void run() {
try {
// Set up a server to listen at port 2901
server = new ServerSocket(2901);
// Keep on running and accept client connections
while(true) {
// Wait for a client to connect
Socket client = server.accept();
addClient(client.getInetAddress().getHostName(), client);
// Start a new client reader thread for that socket
new Thread(new ClientReaderThread(client)).start();
}
} catch (IOException e) {
showError("Could not set up server on port 2901. Application will terminate now.");
System.exit(0);
}
}
}
As you can see, I have an infinite loop while(true) in there, so this thread will never stop unless somehow I stop it.
The right way to do this would be to close the server socket. This will cause the accept() to throw an IOException which you can handle and quit the thread.
I'd add a public void stop() method and make the socket a field in the class.
private ServerSocket serverSocket;
public ClientConnectionThread() {
this.serverSocket = new ServerSocket(2901);
}
...
public void stop() {
serverSocket.close();
}
public void run() {
while(true) {
// this will throw when the socket is closed by the stop() method
Socket client = server.accept();
...
}
}
Generally you don't. You ask it to interrupt whatever it is doing using Thread.interrupt().
A good explanation of why is in the Javadoc.
From the link:
Most uses of stop should be replaced by code that simply modifies some
variable to indicate that the target thread should stop running. The
target thread should check this variable regularly, and return from
its run method in an orderly fashion if the variable indicates that it
is to stop running. (This is the approach that the Java Tutorial has
always recommended.) To ensure prompt communication of the
stop-request, the variable must be volatile (or access to the variable
must be synchronized).
It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either.
For your specific situation you will have to call serverSocket.close, since it does not respond to Thread.interrupt.
I have the following logic (simplified):
public class Application {
public static volatile boolean stopServer;
private static ScheduledExecutorService taskScheduler;
private static Thread listenerThread;
public static synchronized void switchStopServer() {
stopServer = true;
listenerThread.interrupt();
taskScheduler.shutdownNow();
}
public static void main(String[] args) {
int threadPoolSize = 4;
taskScheduler = Executors.newScheduledThreadPool(threadPoolSize);
listenerThread = new ListenerThread();
taskScheduler.schedule(listenerThread, 0, TimeUnit.NANOSECONDS);
}
}
public class ListenerThread extends Thread {
private static ServerSocket serverSocket;
private Socket socketConnection;
#Override
public void run() {
while (!Application.stopServer) {
try {
socketConnection = serverSocket.accept();
new CommunicatorThread(socketConnection).start();
} catch (SocketException e) {
} catch (Exception e) {
}
}
}
private static void closeServerSocket() {
try {
if (serverSocket != null && !serverSocket.isClosed()) serverSocket.close();
} catch (Exception e) { }
}
#Override
public void interrupt() {
closeServerSocket();
super.interrupt();
}
}
What I want to achieve, is to terminate Threads the proper way. First of all, is this (switchStopServer()) the correct way to do that, or are there any better solutions?
I'm a little confused with the ScheduledExecutorService, because shutdownNow() does not interrupt the Threads, neither does ScheduledFuture.cancel(true) (at least for me it doesn't), so I can't interrupt ServerSocket.accept(). I know, in my example there is no need for the ScheduledExecutorService, but in my real application there is.
Your problem I believe is that you are confusing Thread and Runnable. Even though ListenerThread extends Thread, it is actually not it's own thread. The thread is managed by the ExecutorService thread-pool which is just calling your run() method. This is only [sort of] working because Thread also implements Runnable. When you call ListenerThread.interrupt() you are not interrupting the thread in the thread-pool although you are calling your interrupt() method but just directly in the calling thread. This should close the socket since it calls closeServerSocket() from the outside.
When you call ScheduledFuture.cancel(true) or shutdownNow(), the pool thread(s) should be interrupted but this will not call your interrupt() method there. You can test for the interruption by using Thread.currentThread().isInterrupted() in your run() method.
You should change ListenerThread from extending Thread and instead have it just implement Runnable (see edit below). You will want to do something like the following loop in your run() method:
while (!Application.stopServer && !Thread.currentThread().isInterrupted()) {
To interrupt the accept() method, you are going to have to close the serverSocket from another thread. Most likely this will be done by the thread that is calling interrupt(). It should close the socket, shutdownNow() or cancel() the thread-pool, and then it can wait for the pool to terminate.
Edit:
Actually, I wonder why you are using a pool for your ListenerThread since there will only ever be one of them, it is being scheduled immediately, and it is just starting a new thread on any connection directly. I would remove your taskScheduler pool entirely, keep ListenerThread extending Thread, and just call new ListenerThread().start();.
The outer thread would still just close the serverSocket to stop the ListenerThread. If you also need to close all of the connections as well then the ListenerThread needs to keep a collection of the socketConnection around so it can call close() on them when the accept() throws a n IOException.
Also, currently you have private Socket socketConnection; which is misleading because it will change after every call to accept(). I'd rewrite it as:
Socket socketConnection = serverSocket.accept();
new CommunicatorThread(socketConnection).start();
I create a class that allows me to open a single instance of my Java program. It uses a daemon thread that open a ServerSocket. if the TCP Port was already taken throws an exception at instantiation time.
The code works normally under linux and windows.
Here is the code i am using:
public class SingleInstaceHandler extends Thread {
private static final Logger log = Logger.getLogger(IEPLC_Tool.class);
private boolean finished = false;
#SuppressWarnings("unused")
private ServerSocket serverSocket;
/*
* Constructor
* Generate the server socket.
* If the TCP door was busy throws IOException.
*/
public SingleInstaceHandler() throws IOException {
#SuppressWarnings("unused")
ServerSocket serverSocket = new ServerSocket(44331);
this.setDaemon(true);
this.start();
log.info("Server socket initialized"); //if commented out it works
}
public void run() {
synchronized (this) {
while (!finished) {
try {
log.debug("Server socket goes to sleep");
this.wait();
log.debug("Server socket waken up");
} catch (InterruptedException e) {
log.debug("ERROR while sending SocketThread2 in wait status");
e.printStackTrace();
System.exit(-1);
}
log.info("Server socket end");
}
}
}
public synchronized void shutdown() {
log.debug("SingleInstaceHandler shutdown() caled");
finished = true;
notifyAll();
}
}
Sometimes instead the port is not kept busy... any idea?
UPPENDED AFTER FURTHER TESTS:
running many other tests. it seams that if the port is taken by something like another SW instance new ServerSocket(44331); throws an exception but sometimes even if the port is not taken for some reason it can not get this resource. in this case no exception is launched and i can open as many instance as i want of my application. maybe i should do some other operation to force the thread to lock the port...
any idea?
Thanks,
Ste
As you are not keeping a reference to the ServerSocket it will be eligible for GC. If you are using the Oracle JDK the socket will be closed when it is GCed (java.net.PlainSocketImpl).
I do feel a bit stupid in posting an answer to my question... well.. my code has a bug that took me long to figure out:
the problem is that in te constructor i do:
ServerSocket serverSocket = new ServerSocket(44331);
instead of:
this.serverSocket = new ServerSocket(44331);
I did not notice it before... basicaly the bug was that I was declaring a local socket within the constructor. When the constructur procedure was terminated the socket was released or not depending on the Garbadge Collector. Behavior was quite random. Funny part was that plenty of time calling/not calling the logger was enougth to make the Garbadge collector starting or not. It took me quite a while in noticing the mistake.
furthermore it's better to put a :
this.serverSocket.close() after the wait.
Thans for helping anyway!
Cheers,
Ste