简体   繁体   中英

java server Socket sending data to wrong Client

As the title says if you try to execute this program, start 2 clients, and try to send a message 'login' or 'register' with the first client the server will receive the input but redirect the response to the second socket (the last one who connected). You can see this by looking at the port number printed on Server console when Server tries to send response to client

public class Server {
    private ServerSocket server;

    public Server() {
        try {
            server = new ServerSocket(10000);
            System.out.println("[INFO] server running");
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.run();
    }

    public void run() {
        try {
            while (true) {
                Socket clientRequest = server.accept();
                new Thread(new ServerThread(clientRequest)).start();
            }
        } catch (IOException e) {
            System.out.println(e);
        }
    }
}
class ServerThread implements Runnable {
    private static Socket socket;

    private static Connection dbConnection = null;
    private static OutputStream outputStream;
    private static ObjectOutputStream objectOutputStream;
    private static InputStream inputStream;
    private static ObjectInputStream objectInputStream;

    private static List<String> messages = new ArrayList<String>();
    private static MessageDigest messageDigest;

    private static String username = "";
    private static boolean invalidUsername;

    public ServerThread(Socket richiestaClient) {
        try {
            socket = richiestaClient;
            System.out.println("[INFO] " + socket + " connected ");
            outputStream = socket.getOutputStream();
            objectOutputStream = new ObjectOutputStream(outputStream);
            inputStream = socket.getInputStream();
            objectInputStream = new ObjectInputStream(inputStream);
        } catch (IOException e) {
            System.out.println("[ERROR] errore di i/o");
        }
    }

    public void run() {
        // conversazione lato server
        try {
            boolean active = true;
            while (active) {
                System.out.println("[THREAD] " + Thread.currentThread().getName());
                System.out.println("[DEBUG] current socket: " + socket);
                String msg = (String) objectInputStream.readObject();
                System.out.println("[CLIENT] " + msg);
                // -- SELECT CASE FOR USER LOGIN/REGISTER --
                switch (msg) {
                    case "login":
                        login(dbConnection);
                        break;
                    case "register":
                        register(dbConnection);
                        break;
                    default:
                        break;
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("[ERROR] errore nello switch azioni ioexception " + e);
        }
    }

    private static void register(Connection dbConnection) {
        System.out.println("[THREAD] " + Thread.currentThread().getName());
        System.out.println("[DEBUG] client selected register " + socket);
        messages.add("username");
        messages.add("You selected register");
        invalidUsername = true;
        while (invalidUsername) {
            messages.add("input the username you want");
            send(messages);
            // getting username (assuming not taken for testing purpose)
            boolean usernameExists = false;
            if (usernameExists) {
                System.out.println("[DEBUG] username exists, not available for the registration");
                messages.add("username");
                messages.add("sorry, username is taken :(");
            } else {
                System.out.println("[DEBUG] username does not exists, available for the registration");
                messages.add("password");
                messages.add("username is not taken yet :)");
                invalidUsername = false;
            }
        }
        System.out.println("[DEBUG] username not taken, sending result to " + socket);
    }

    private static void login(Connection dbConnection) {
        System.out.println("[THREAD] " + Thread.currentThread().getName());
        System.out.println("[DEBUG] client selected login " + socket);
        messages.add("username");
        messages.add("You selected login");
        messages.add("Input your username");
        send(messages);
        try {
            username = (String) objectInputStream.readObject();
            System.out.println("[INFO] received " + username + " from " + socket);
        } catch (ClassNotFoundException | IOException e) {
            System.out.println("[DEBUG] error while waiting for client login username");
        }
    }

    // sending messages, flushing stream and clearing messages list
    private static void send(List<String> messagesToSend) {
        System.out.println("[THREAD] " + Thread.currentThread().getName());
        System.out.println("[DEBUG] Sending data to " + socket);
        try {
            objectOutputStream.writeObject(messagesToSend);
            objectOutputStream.flush();
            messages.clear();
        } catch (IOException e) {
            System.out.println("[ERROR] error occurred while sending message");
        }
    }
}
public class Client {
    private static Socket socket;

    private static OutputStream outputStream;
    private static ObjectOutputStream objectOutputStream;
    private static InputStream inputStream;
    private static ObjectInputStream objectInputStream;

    public Client() {
        try {
            socket = new Socket("127.0.0.1", 10000);
            outputStream = socket.getOutputStream();
            objectOutputStream = new ObjectOutputStream(outputStream);
            inputStream = socket.getInputStream();
            objectInputStream = new ObjectInputStream(inputStream);
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    public static void main(String[] args) {
        Client client = new Client();
        client.conversazione();
    }

    public void conversazione() {
        // conversazione lato client
        Scanner scan = new Scanner(System.in);
        String command = "default";
        String message = "";
        String username = "";
        List<String> messages = new ArrayList<String>();
        System.out.println("what do you want to do? (login/register)");
        while (true) {
            try {
                switch (command) {
                    case "default":
                        System.out.println("[DEBUG] switch option: default");
                        message = scan.nextLine();
                        send(message);
                        break;
                    case "username":
                        System.out.println("[DEBUG] switch option: username");
                        username = scan.nextLine();
                        send(username);
                        break;
                    case "password":
                        System.out.println("[DEBUG] switch option: password");
            // not implemented yet
                        break;
                    default:
                        break;
                }
        // getting messages from the server, using the first one as "header" to know what to do
                System.out.println("[DEBUG] waiting for message " + socket);
                messages = (List<String>) objectInputStream.readObject();
                System.out.println("Received [" + (messages.size() - 1) + "] messages from: " + socket);
                command = messages.get(0);
                messages.remove(0);
                for (String msg : messages) {
                    System.out.println(msg);
                }
                messages.clear();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // send message to the server and reset the stream
    public static void send(String message) {
        try {
            System.out.println("[DEBUG] sending data as " + socket);
            objectOutputStream.writeObject(message);
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The "static" keyword in attributes means that the value of the attribute is spread over all objects of the class, since the value is not stored in the object, but, simply put, is stored in the class.

If you don't know exactly what "static" stands for, maybe check out the following page: Static keyword in java

public class Test {
  // static attribute
  private static String hello = "world";

  public void setHello(String newValue) {
    Test.hello = newValue;
  }

  public void printHello() {
    System.out.println(Test.hello);
  }
}

public class Main {
  public static void main(String[] args) {
    Test test1 = new Test();
    Test test2 = new Test();
    test1.printHello(); // -> "world"
    test2.printHello(); // -> "world"

    // Note that we seem to change only the value of "hello" in object "test1". 
    // However, since the attribute "test1" is static, the value "changes" for all objects of the class.
    test1.setHello("StackOverflow");

    test1.printHello(); // "StackOverflow"
    test2.printHello(); // "StackOverflow" <- same as in "test1"
  }
}

The problem is that in your "ServerThread" class all attributes are static, and therefore they are shared across different objects. So if you overwrite the variable "socket" in client 2, you overwrite "socket" on for client 1.

So remove the "static" keyword from attributes and methods of the Client and ServerThread class and that should solve the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM