0

Got a problem about server-client:

When server is running, if I want to make some change in ServerThread, for example, the string "Welcome!" to "Hello!", is that possible to execute that without restart the server? For now, when I change "Welcome!" to something else, it still print out "Welcome!" to client. I have to close eclipse and restart server for this new string working. Is there any way to solve that problem? Thx alot!

Server:

import java.net.*;
import java.io.*;

public class ATMServer {

    private static int connectionPort = 8989;
    public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = null;
    boolean listening = true; 
    try {
        serverSocket = new ServerSocket(connectionPort); 
    } catch (IOException e) {
        System.err.println("Could not listen on port: " + connectionPort);
        System.exit(1);
    }

    System.out.println("Bank started listening on port: " + connectionPort);
    while (listening)
        new ATMServerThread(serverSocket.accept()).start();
    serverSocket.close();
    }
}

ServerThread:

import java.io.*;
import java.net.*;

public class ATMServerThread extends Thread {
    private Socket socket = null;
    private BufferedReader in;
    PrintWriter out;
    public ATMServerThread(Socket socket) {
        super("ATMServerThread");
        this.socket = socket;
    }

    public void run(){
    try {
        out = new PrintWriter(socket.getOutputStream(), true);

        out.println("Welcome!"); 

    } catch (IOException e){
        e.printStackTrace();
        }
    }
}

Client:

import java.io.*;   
import java.net.*;  
import java.util.Scanner;

public class Client {
    private static int connectionPort = 8989;

    public static void main(String[] args) throws IOException {

        Socket ATMSocket = null;
        PrintWriter out = null;
        BufferedReader in = null;
        String adress = "";

        try {
            adress = "127.0.0.1";
        } catch (ArrayIndexOutOfBoundsException e) {
            System.err.println("Missing argument ip-adress");
            System.exit(1);
        }
        try {
            ATMSocket = new Socket(adress, connectionPort); 
            out = new PrintWriter(ATMSocket.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader
                                    (ATMSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Unknown host: " +adress);
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't open connection to " + adress);
            System.exit(1);
        }

        System.out.println(in.readLine());


        out.close();
        in.close();
        ATMSocket.close();
    }
}
Perception
  • 79,279
  • 19
  • 185
  • 195
Ferry
  • 583
  • 8
  • 18
  • This question is an example of why IDE's are sometimes a dangerous tool for new developers. @Ferry, you will learn ALOT about Java if you take this code you have written and play with it awhile OUTSIDE of Eclipse. Then come back here and reformulate your question. – Perception Nov 03 '11 at 13:20

5 Answers5

3

This is possible but not simple.

The string "Welcome!" is part of the class file (it's a static String constant). When you change it, Eclipse will create a new .class file and write that to disk.

At the same time, you have a running Java program which uses the same .class file. There are two reasons why the change isn't picked up:

  1. A Java VM doesn't reload class files by itself. When a class has been loaded once, it doesn't update when you change the .class file on the disk. You have to tell the classloader to flush the loaded class from memory and load the .class file again.

  2. There is an instance of this class in the running VM. The instance has a reference to a String object. Even when the class is loaded again, this instance (and its references) don't change. You have to create a new instance.

To fix the first problem, you need to run your application in Debug mode. Eclipse will then try to tell the VM when .class files have changed. Note that some changes can't be reloaded by some VMs. For example, Sun's VM can handle new methods, method parameters, fields, imports. You can only change method bodies. Eclipse will tell you when the reload has failed.

To fix the second issue, stop the thread and start a new one. I suggest a special client "restart" message for this which stops all threads and creates a new pool.

In any case, it's never necessary to stop Eclipse.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
2

I suspect you misunderstand in the following way -

  • you hit 'Run' in Eclipse, and your server launches
  • you test with the client
  • you change the server
  • you hit 'Run' again
  • you test with the client and see no changes

What happens here is that the second time you hit run, your server fails to start because the previous one is still running & so the new one can not acquire the listen socket.

You don't need to restart Eclipse to terminate the running process, just go to the Console view, use the "Open Console" drop down (very right) in the toolbar to find your running server process and stop it using the red stop button (very left).

themel
  • 8,825
  • 2
  • 32
  • 31
  • Thx. But your method still required to reboot the server. Just think if the server is not mine, and I've only got serverThread and client-part and I want to change the string and make this work. Is that possible? – Ferry Nov 03 '11 at 13:17
0

Create a setter method on your thread for the variables you wish to change. When you instantiate the thread, keep a handle to the thread you created. Then simply call the setter method for the variable.

Thom
  • 14,013
  • 25
  • 105
  • 185
0

"Add dynamic Java code to your application" http://www.javaworld.com/javaworld/jw-06-2006/jw-0612-dynamic.html

Vitali Pom
  • 602
  • 1
  • 8
  • 29
-1

I'm not sure I fully understand your question, but I think I know what you're talking about. I believe what is happening is you're application isn't closing the socket when you end it. In Windows, I'm not sure that there is a way to close that socket outside the process that opened it, but in Linux you can do and lsof then kill that pid.

lsof -i tcp:8989
kill -9 some_PID
bdeetz
  • 185
  • 1
  • 1
  • 13
  • In order to properly close the socket, catch the interrupt or keystroke you are using to end the application and call a function inside the thread to end the work portion and close the socket. – bdeetz Nov 03 '11 at 12:49
  • This doesn't make any sense. If the application ends, (a) the OS releases all resources including open sockets, and (b) there is no process left to kill. – user207421 May 22 '12 at 22:51
  • @EJP It may not make sense, but that doesn't change the fact that I'm correct to some degree... http://stackoverflow.com/questions/2270343/cannot-bind-to-address-after-socket-program-crashes In his case, I am wrong. He is closing the socket and when I originally answered the question I overlooked that. But, you can have applications crash that leave sockets in a TIME_WAIT state. When that happens, you can kill the PID associated with that socket and regain the ability to open the socket again. – bdeetz May 23 '12 at 23:28